﻿/// <reference path="GMAPJSHelper_Release.js" />
/// <reference path="vswd-ext_2.2.js" />

/*************************************************
Author :Winston
Create : 2009-11
*/
Array.prototype.insertAt = function(index, value) {
    var part1 = this.slice(0, index);
    var part2 = this.slice(index);
    part1.push(value);
    return (part1.concat(part2));
};

Array.prototype.removeAt = function(Index) {
    if (isNaN(Index) || Index > this.length) { return false; }
    for (var i = 0, n = 0; i < this.length; i++) {
        if (this[i] != this[Index]) {
            this[n++] = this[i]
        }
    }
    this.length -= 1
}

var EnumMapToolType = {
    Pan: 0,
    GeoFenceInAlarm: 1,
    GeoFenceOutAlarm: 2,
    AddPOI: 3,
    BeginEditMovePOI: 4,
    EndEditMovePOI: 5,
    CircleGeoFenceInAlarm: 6,
    CircleGeoFenceOutAlarm: 7,
    CircleGeoFenceInOutAlarm: 8,
    DrawDefinedRoute: 9,

    StreetMode: 10,
    DrawPolygonGeoFenceInAlarm: 11,
    DrawPolygonGeoFenceOutAlarm: 12,
    DrawPolygonGeoFenceInOutAlarm: 13
};

var EnumEarthState = {
    Undone: 0,
    Done: 1,
    Unknown: 2
};

GMap2.prototype.setContainerClass = function(obj) {
    this._containerclass = obj;
};

GMap2.prototype.getContainerClass = function() {
    return this._containerclass;
};

Array.prototype.clear = function() { this.length = 0; };

/***************************Auth:Winston create in 2010-5******************/
//google map Extent for LBS device Location drived by GOverlay

var svgNS = "http://www.w3.org/2000/svg";

function isIE10() {
    if (navigator.appName == "Microsoft Internet Explorer") {
        if (navigator.appVersion.match(/10./i) == '10.') {
            return true;
        }
        else {
            return false;
        }
    }
}

if (document.createStyleSheet) {
    if (isIE10()) {
    }
    else {
        document.createStyleSheet().addRule("v\\:oval", "behavior:url(#default#VML);display:inline-block;");
        document.createStyleSheet().addRule("v\\:fill", "behavior:url(#default#VML);display:inline-block;");
        document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
    }
}
else if (document.createElementNS) {
    //Browser Support SVG
}

function ExLBSDevice(point, d, imagesrc) {
    this.point = point;
    this.radius = d / 2;
    var icon = new GIcon();
    icon.iconSize = new GSize(40, 40);
    icon.infoWindowAnchor = new GPoint(44, 30);
    icon.image = imagesrc;
    icon.iconAnchor = new GPoint(16, 32);
    this.icon = icon;
    this.imagesrc = imagesrc;
}

ExLBSDevice.prototype = new GOverlay();
ExLBSDevice.prototype.getPoint = function() {
    return this.point;
}
ExLBSDevice.prototype.getIcon = function() {
    return this.icon;
}

ExLBSDevice.prototype.initialize = function(map) {
    var div = document.createElement("div");
    div.style.position = "absolute";
    map.getPane(G_MAP_MAP_PANE).appendChild(div);
    this.map = map;
    this.div = div;
};

// Remove the main DIV from the map pane
ExLBSDevice.prototype.remove = function() {
    this.div.parentNode.removeChild(this.div);
    //this.div2.parentNode.removeChild(this.div2);
};

// Copy our data to a new ExRectangle
ExLBSDevice.prototype.copy = function() {
    return new ExLBSDevice(this.point, this.radius, this.imagesrc);
};

ExLBSDevice.prototype.setLatLng = function(pt) {
    this.point = pt;
    this.redraw(true);
};

ExLBSDevice.prototype.getLatLng = function() {
    return this.point;
};
// Redraw the ExRectangle based on the current projection and zoom level

ExLBSDevice.prototype.redraw = function(force) {
    if (!force) return;
    //Clear all div items

    this.div.innerHTML = "";
    var bounds = this.map.getBounds();
    var c3 = this.map.fromLatLngToDivPixel(this.point);
    var southWest = bounds.getSouthWest();
    var northEast = bounds.getNorthEast();
    var r = Math.abs((this.radius / ((northEast.lng() - southWest.lng()) * 3.14 * 6370000 / 180)) * 710);
    if(r<1)
        r=1;
    //if(r<3) 
    //	r=3;
    this.div.style.width = (2 * r).toString() + "px";
    this.div.style.height = (2 * r).toString() + "px";
    this.div.style.left = (c3.x - r).toString() + "px";
    this.div.style.top = (c3.y - r).toString() + "px";
    //this.div.style.backgroundColor = 'red';
    if (document.createStyleSheet && (!isIE10())) {
        var browser = navigator.appName
        var b_version = navigator.appVersion
        var version = parseFloat(b_version)
        if (version < 5) {
            var bigoval = document.createElement("v:oval");
            bigoval.style.position = "absolute";
            bigoval.strokeColor = '#3399FF';
            bigoval.strokeWeight = 1;
            bigoval.style.left = 0;
            bigoval.style.top = 0;
            bigoval.style.width = 2 * r;
            bigoval.style.height = 2 * r;
            bigoval.style.opacity = 0.5;
            var MacdStroke = document.createElement('<v:fill opacity="0.1" color="#3399FF" />');
            bigoval.insertBefore(MacdStroke);
            this.div.appendChild(bigoval);
        }
        else {
            var content = document.createElementNS(svgNS, "svg");
            var bigoval = document.createElementNS(svgNS, "circle");
            bigoval.style.position = "absolute";
            bigoval.setAttribute("shape-rendering", false);
            bigoval.setAttribute("stroke-width", "1px");
            bigoval.setAttribute("stroke-color", '#3399FF');
            bigoval.setAttribute("r", (r - 1));
            bigoval.setAttribute("cx", (r + 1) + "px");
            bigoval.setAttribute("cy", (r + 1) + "px");
            bigoval.setAttribute("stroke", '#3399FF');
            bigoval.setAttribute("fill", "#3399FF");
            bigoval.setAttribute("fill-opacity", "0.1");
            bigoval.style.left = 4;
            bigoval.style.top = 4;
            content.appendChild(bigoval);
            this.div.appendChild(content);
        }

    }
    else if (document.createElementNS) {
        var content = document.createElementNS(svgNS, "svg");
        var bigoval = document.createElementNS(svgNS, "circle");
        bigoval.style.position = "absolute";
        bigoval.setAttribute("shape-rendering", false);
        bigoval.setAttribute("stroke-width", "1px");
        bigoval.setAttribute("stroke-color", '#3399FF');
        bigoval.setAttribute("r", (r - 1));
        bigoval.setAttribute("cx", (r + 1) + "px");
        bigoval.setAttribute("cy", (r + 1) + "px");
        bigoval.setAttribute("stroke", '#3399FF');
        bigoval.setAttribute("fill", "#3399FF");
        bigoval.setAttribute("fill-opacity", "0.1");
        bigoval.style.left = 4;
        bigoval.style.top = 4;
        content.appendChild(bigoval);
        this.div.appendChild(content);
    }
    var img = document.createElement("img");
    img.style.position = "absolute";
    img.src = this.imagesrc;
    img.style.width = 40;
    img.style.height = 40;
    var left = (r - img.width / 2);
    var top = (r - img.height / 2);
    img.style.left = left.toString() + "px";
    img.style.top = top.toString() + "px";
    this.div.appendChild(img);

};



function poiInfo(poiid, name, latitude, longitude, iconindex) {
    this.poiid = poiid;
    this.name = name;
    this.latitude = latitude;
    this.longitude = longitude;
    this.iconindex = iconindex;
};

/*******************************Class MSGMap ****************
this class packaged the google map and mlg function

**************************************************************/



var MSGMap = function (gmap, smallcontrol, fncallback, mapurl, start, stop, cont, hasearth, panorama) {
    this.History_points = [];
    this.smallcontrol = smallcontrol;
    this.map = gmap; // the google map class 
    var containClass = this;
    this.meiEarth = null;
    this.hasEarth = hasearth;

    this.earthState = EnumEarthState.Undone; //google earth state

    this.startbtn = start;
    this.stop = stop;
    this.contin = cont;


    var G_CHINA_MAP;
    var G_OPENSTREET_MAP;


    if (mapurl == "maps.google.com") {
        var copyOSM = new GCopyrightCollection("<a href=\"http://www.openstreetmap.org/\">OpenStreetMap</a>");
        copyOSM.addCopyright(new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180)), 0, " "));

        var tilesMapnik = new GTileLayer(copyOSM, 1, 17, { tileUrlTemplate: 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png' });
        //var tilesOsmarender = new GTileLayer(copyOSM, 1, 17, { tileUrlTemplate: 'http://tah.openstreetmap.org/Tiles/tile/{Z}/{X}/{Y}.png' });

        G_OPENSTREET_MAP = new GMapType([tilesMapnik], G_NORMAL_MAP.getProjection(), "OpenStreet");

        //var mapOsmarender = new GMapType([tilesOsmarender], G_NORMAL_MAP.getProjection(), "Osmarend");
        //this.gmap = new GMap2(this.body.dom, { mapTypes: [mapMapnik, mapOsmarender]});

        this.map.addMapType(G_OPENSTREET_MAP);
        //this.map.addMapType(mapOsmarender);
    }
    else if (mapurl == "ditu.google.com") {

        var chinaTileLayer = new GTileLayer(new GCopyrightCollection(""), 1, 17);
        chinaTileLayer.getTileUrl = function (tile, zoom) {
            zoom = this.maxResolution() - zoom;
            var s = "http://emap1.mapabc.com/mapabc/maptile?v=w2.61&zoom=" + zoom + "&x=" + tile.x + "&y=" + tile.y;
            return s;
        };
        G_CHINA_MAP = new GMapType([chinaTileLayer], new GMercatorProjection(23), "中国地图");
        this.map.addMapType(G_CHINA_MAP);
    }
    this.map.setContainerClass(this);

    var _msgmap = this;
    var _mapurl = mapurl;

    if (smallcontrol) {
        this.map.addControl(new GSmallMapControl());
        this.map.addControl(new GMapTypeControl());
        if (hasearth)
            this.map.addMapType(G_SATELLITE_3D_MAP);

    }
    else {
        this.map.addControl(new GLargeMapControl());
        this.map.addControl(new GMapTypeControl());
        this.map.addControl(new GScaleControl());
        //this.map.addControl(new GOverviewMapControl());
        if (hasearth) {
            this.map.addMapType(G_SATELLITE_3D_MAP);
            //            if (window.MeiEarth && this.meiEarth == null) {
            //                this.meiEarth = new MeiEarth(this); //google earth extension class  
            //            }
        }
        //        try {
        //            this.map.addControl(new google.maps.LocalSearch(), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(120, 3)));
        //        }
        //        catch (err) {
        //        }
    }
    if (panorama)
        this._gsvPanorama = panorama.getMap();



    this.map.enableScrollWheelZoom();
    this._trackerinfoLastArray = []; // array for tracker info 
    this._vehicleOverlayerArray = []; //array for last point vehicle
    this._labelOverlayerArray = []; //arry for last point vehicle lable
    this._bolfirsttimeload = true;
    this._bounds = null;
    this._geocoder = new GClientGeocoder();
    this._svOverlay = new GStreetviewOverlay();




    this._isdragging = false;
    this._maptooltype = EnumMapToolType.Pan;
    this._dragrectbeginlatlng; //Drag rectangle being latlng
    this._dragrectendlatlng; //Drag rectangle end latlng
    this._dragRectangle;
    this.FnGeoFenceCallBack; // function call back for draw geo fence end

    this._preRadiusGeoFenceOverlay; //drag Geo fence  overlay
    this._circleGeoFenceOverlayArray; //show Circle GeoFence overlay
    this.FnCircleGeoFenceCallBack; // function circle geofence call back
    this._circleGeoFenceCenter; //the center of drag geofence
    this._circleEndLatLng; // the end latlng of drag geofence

    this._realtimeTrackingLine; // realtime tracking google line overlay
    this._realtimeOverlayArray = []; //realtime point overlay array

    this._historyLine; //history tracking line overlay
    this._historyOverlayArray = []; //history point overlay array

    this._poiOverlayArray = []; //all poi overlay
    this._addPOIOverlay; //add new poi overlay
    this._movePOIOverlay; //move poi overlay
    this._movePOIInfo;

    this._findOutLocationOverlay;

    this._directions;
    this._directionsPanel;

    this._previousmaptype = G_NORMAL_MAP;
    this._submitcap = "Submit";
    this._cancelcap = "Cancel";
    this._latitude = "Latitude";
    this._longitude = "Longitude";

    this._historyshowindex = 0;
    this._animateinterval = 1000;
    this._stopanimate = false;
    this._trackerhistoryinfoArray = [];
    this._historyshowtimer;
    this._gpsTimeCap = "";
    this._speedCap = "";
    this._parkingTimeCap = "";
    this._submitAddRouteCap = "";
    this._submitAddAllRouteCap = "";
    this._cancelAddRouteCap = "";
    this._editRouteID = null;
    this._closeCap = "";
    this._farCap = "";
    this._iniDrawRoute = false;
    this._finishDrawRoute = false;
    this._routePolys = [];
    this._waypoints = [];
    this._routeNodes = [];
    this._isEditMode = false;
    this.GDir1 = new GDirections(), this.GDir2 = new GDirections();
    this._normalProj = G_NORMAL_MAP.getProjection(),
    this._init_route = [],
    this._myPoints = [],
    this._markerDragged,
        this._isDragged,
         this._lastIndex,
          this._prevIndex;
    this._isMyDragging = false;
    this._isFirstDragMyNode = true, this.isMyDragging = false;
    this.myPoints = [];
    this._myNode = this.getMyDragNodeMarker(_msgmap);
    this.map.addOverlay(this._myNode);
    this._myNode.show(); // sometimes .hide() does not work without .show() at first ???
    this._myNode.hide(); // hide this marker initially
    this._isMyNodeStartDrag = false;
    this._tempRoutes = new Array();
    this._modifyRouteIndex = 0;
    this._routePrevbutton = null;
    this._routeNextButton = null;
    this._routeTempPoint = null;
    this._callbackDrawPolyline = null; //绘制路线时的回调函数
    this._fnAddPolygonFence = null;
    this._fnEditPolygonFence = null;
    this._polygonGeofencePoints = new Array();
    this._polygonGeofence = null; //多边形
    this._polygonGeofenceVertexs = new Array(); //多边形各个端点
    this._polygonGeofencePaths = new Array(); //多边形各条边
    this._polygonFenceShowArray = new Array(); //用来显示多边形电子围栏集合
    this._callbackDrawPolygon = null; //绘制多边形时的回调函数
    this._polygonViewModel = true; //true代表显示所有,false代表隐藏所有
    this._editPolygonFence = this.createPolygon(true, [], true); //用来显示编辑状态的多边形电子围栏

    this.map.addOverlay(this._editPolygonFence);
    this._editPolygonFenceStatus = false; //编辑状态
    this._historylineendfn = null;
    this._hidehistoryline = false;

    this._polygonGeofence = this.createPolygon(false, [], true);
    this.map.addOverlay(this._polygonGeofence);
    this._polygonGeofence.hide();
    GEvent.addListener(this.GDir1, "load", function () {
        var gp = this.getPolyline();
        var count = gp.getVertexCount();
        var tempPoints = Array();
        var point;
        for (var i = 0; i < count; i++) {
            var tempPoint = gp.getVertex(i);
            tempPoints.push({ point: tempPoint });
            if (i == count - 1) {
                point = tempPoint;
            }
        }

        var marker = _msgmap.getStartAndEndMarker(point, _msgmap);
        marker.MyIndex = _msgmap._waypoints.length;
        _msgmap._waypoints.push(marker);
        _msgmap.map.addOverlay(marker);
        if (_msgmap._waypoints.length > 1) { // if this was not the first waypoint - display the route to this waypoint
            _msgmap.map.addOverlay(gp);
            _msgmap._routePolys.push(gp);
            _msgmap._routeNodes = [];
            _msgmap.getProximity();
        }
        if (_msgmap._callbackDrawPolyline) {
            _msgmap._callbackDrawPolyline(tempPoints);
        }
    });
    GEvent.addListener(this.GDir1, "error", function (a, b, c, d, e) {
        var marker = _msgmap.getStartAndEndMarker(_msgmap._routeTempPoint, _msgmap);
        marker.MyIndex = _msgmap._waypoints.length;
        _msgmap._waypoints.push(marker);
        _msgmap.map.addOverlay(marker);
        var points = new Array();
        if (_msgmap._waypoints.length > 1) { // if this was not the first waypoint - display the route to this waypoint
            for (var i = 0; i < _msgmap._waypoints.length; i++) {
                points.push(_msgmap._waypoints[i].getLatLng());
            }
            var gp = new GPolyline(points, "blue", 5, 0.5);
            _msgmap.map.addOverlay(gp);
            _msgmap._routePolys.push(gp);
            _msgmap._routeNodes = [];
            _msgmap.getProximity();
        }
        var tempPoints = Array();
        for (var i = 0; i < points.length; i++) {
            var tempPoint = points[i];
            tempPoints.push({ point: tempPoint });
        }
        if (_msgmap._callbackDrawPolyline) {
            _msgmap._callbackDrawPolyline(tempPoints);
        }
    });

    GEvent.addListener(this._myNode, "dragstart", function () { // mouse was over displayed route and user drags the displayed marker
        _msgmap._isMyNodeStartDrag = true;
    });
    GEvent.addListener(this._myNode, "drag", function () { // mouse was over displayed route and user drags the displayed marker
        this.show();

    });
    GEvent.addListener(this._myNode, "dragend", function () {
        _msgmap._isMyDragging = true;
        var poly = _msgmap._routePolys[this.MyIndex];
        //first time
        if (_msgmap._tempRoutes.length == 0) {
            var firstPoints = [];
            for (var i = 0; i < poly.getVertexCount(); i++) {
                firstPoints.push(poly.getVertex(i));
            }
            _msgmap._tempRoutes.push(new GPolyline(firstPoints, "blue", 5, 0.5));
        }
        if (_msgmap._isFirstDragMyNode) {
            _msgmap._myPoints = [];
            var stepPoints = [];
            poly.insertVertex(this.NodeIndex, this.getLatLng());
            var point = _msgmap._normalProj.fromLatLngToPixel(this.getLatLng(), _msgmap.map.getZoom());
            _msgmap._routeNodes = _msgmap._routeNodes.insertAt(this.NodeIndex, { point: point, lineindex: this.MyIndex });
            var isAddNodeIndexPoint = false;

            for (var i = 0; i < poly.getVertexCount(); i++) {
                if (i == this.NodeIndex && isAddNodeIndexPoint == false) {
                    _msgmap._myPoints.push(this.getLatLng());
                    stepPoints.push(this.getLatLng());
                    i--;
                    isAddNodeIndexPoint = true;
                }
                else {
                    _msgmap._myPoints.push(poly.getVertex(i));
                    stepPoints.push(poly.getVertex(i));
                }
            }
            _msgmap._isFirstDragMyNode = false;

            if (_msgmap._modifyRouteIndex < _msgmap._tempRoutes.length - 1) {
                for (var i = _msgmap._modifyRouteIndex + 1; i < _msgmap._tempRoutes.length; i++) {
                    _msgmap._tempRoutes.removeAt(i);
                }

            }

            _msgmap._modifyRouteIndex++;
            var nGpoly = new GPolyline(stepPoints, "blue", 5, 0.5);
            _msgmap._tempRoutes.push(nGpoly);

            if (_msgmap._tempRoutes.length > 1) {
                _msgmap._routeNextButton = devtoolbar.items.items[devtoolbar.items.items.length - 1];
                _msgmap._routePrevButton = devtoolbar.items.items[devtoolbar.items.items.length - 2];
                _msgmap._routePrevButton.setDisabled(false);
                if (_msgmap._tempRoutes.length - 1 >= _msgmap._modifyRouteIndex)
                    _msgmap._routeNextButton.setDisabled(true);
            }

        }
        _msgmap._isMyNodeStartDrag = false;
        if (_msgmap._callbackDrawPolyline) {
            _msgmap._callbackDrawPolyline(_msgmap._routeNodes);
        }
    });

    //static value
    var baseIcon = new GIcon();
    baseIcon.iconSize = new GSize(32, 32);
    //baseIcon.shadowSize = new GSize(37, 34);
    baseIcon.iconAnchor = new GPoint(16, 16);
    baseIcon.infoWindowAnchor = new GPoint(9, 2);
    baseIcon.infoShadowAnchor = new GPoint(18, 25);

    GEvent.addListener(this.map, 'mousemove', function (point) { _msgmap.getProximity(point); }); // for detecting if mouse is above displayed route

    GEvent.addListener(this.map, "zoomend", function () {
        this.getContainerClass()._routeNodes = []; // clear cached coordinates in pixels of displayed route vertexes, the coordinates have to be recalculated on new zoom level
    });

    GEvent.addListener(this.map, "click", function (overlay, latlng) {
        this.getContainerClass().maponclick(overlay, latlng);
    });

    GEvent.addListener(this.map, "maptypechanged", function () {
        if (this.getCurrentMapType() == G_SATELLITE_3D_MAP) {
            if (window.MeiEarth && this.getContainerClass().meiEarth == null) {
                this.getContainerClass().meiEarth = new MeiEarth(this.getContainerClass()); //google earth extension class  
            }
        }
        if (_mapurl == "maps.google.com") {
            if (this.getCurrentMapType() == G_NORMAL_MAP) {
                this.getContainerClass().reviseAllOverlay();
            }
            else {
                if (this._previousmaptype == G_NORMAL_MAP)
                    this.getContainerClass().unReviseAllOverlay();
            }
        }
        else if (_mapurl == "ditu.google.com") {
            if (this.getCurrentMapType() == G_SATELLITE_3D_MAP) {
                if (this.getContainerClass().smallcontrol) {
                    if (window.MeiEarth && !this.getContainerClass().meiEarth)
                        this.getContainerClass().meiEarth = new MeiEarth(this.getContainerClass()); //google earth extension class
                    else {
                        this.getContainerClass().resetStartBtn(containClass.startbtn, containClass.stop, containClass.contin);
                        this.getContainerClass().meiEarth.ClearAllOfEarthMarker();
                    }
                }
                this.getContainerClass().redrawDefinedRouteToMap();
            }
            else {
                this.getContainerClass().solveExcursionFromEarth();
                if (this.getContainerClass().smallcontrol && this.getContainerClass().meiEarth)
                    this.getContainerClass().meiEarth.ToInitDSCarForChangeMapType();
                this.getContainerClass().redrawDefinedRouteToEarth();
            }
            if (this._previousmaptype == G_SATELLITE_3D_MAP && this.getContainerClass().smallcontrol) {
                this.getContainerClass().resetStartBtn(containClass.startbtn, containClass.stop, containClass.contin);
            }
        }
        this._previousmaptype = this.getCurrentMapType();
    });

    GEvent.addListener(this.map, "mousemove", function (latlng) {
        var msgmap = this.getContainerClass();
        if (msgmap._maptooltype == EnumMapToolType.GeoFenceInAlarm || msgmap._maptooltype == EnumMapToolType.GeoFenceOutAlarm) {
            //Draw rectangle geoFence overlay
            if (msgmap._dragRectangle != null)
                msgmap.map.removeOverlay(msgmap._dragRectangle);
            if (msgmap._isdragging && (msgmap._dragrectbeginlatlng != null)) {
                var color = 'red';
                switch (msgmap._maptooltype) {
                    case EnumMapToolType.GeoFenceInAlarm:
                        color = '#ff0000';
                        break;
                    case EnumMapToolType.GeoFenceOutAlarm:
                        color = '#00fa98';
                        break;
                }

                msgmap._dragRectangle = new GPolygon([
		            new GLatLng(msgmap._dragrectbeginlatlng.lat(), msgmap._dragrectbeginlatlng.lng()),
		            new GLatLng(msgmap._dragrectbeginlatlng.lat(), latlng.lng()),
		            new GLatLng(latlng.lat(), latlng.lng()),
		            new GLatLng(latlng.lat(), msgmap._dragrectbeginlatlng.lng()),
		            new GLatLng(msgmap._dragrectbeginlatlng.lat(), msgmap._dragrectbeginlatlng.lng())
		        ], color, 0, 1, color, 0.2);
                msgmap.map.addOverlay(msgmap._dragRectangle);
                msgmap._dragrectendlatlng = latlng;
                GEvent.addListener(msgmap._dragRectangle, "click", function (overlay, latlng) {
                    msgmap.maponclick(overlay, latlng);
                });
            }
        }
        //Draw Moving POI overlay
        if (msgmap._maptooltype == EnumMapToolType.BeginEditMovePOI && msgmap.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            if (msgmap._movePOIInfo != null) {
                var poiid = msgmap._movePOIInfo.poiid;
                var name = msgmap._movePOIInfo.name;
                var lat = latlng.lat();
                var lng = latlng.lng();
                var iconindex = msgmap._movePOIInfo.iconindex;
                msgmap._movePOIInfo.latitude = lat;
                msgmap._movePOIInfo.longitude = lng;
                msgmap.drawMovePOI(poiid, name, lat, lng, iconindex, msgmap._submitcap, msgmap._cancelcap, null, null);
            }
        }
        //Draw Radius GeoFence overlay
        if (msgmap._maptooltype == EnumMapToolType.CircleGeoFenceInAlarm || msgmap._maptooltype == EnumMapToolType.CircleGeoFenceOutAlarm || msgmap._maptooltype == EnumMapToolType.CircleGeoFenceInOutAlarm) {
            if (msgmap._preRadiusGeoFenceOverlay != null)
                msgmap.map.removeOverlay(msgmap._preRadiusGeoFenceOverlay);
            if (msgmap._isdragging && (msgmap._circleGeoFenceCenter != null)) {
                var color = 'red';
                switch (msgmap._maptooltype) {
                    case EnumMapToolType.CircleGeoFenceInAlarm:
                        color = '#ff0000';
                        break;
                    case EnumMapToolType.CircleGeoFenceOutAlarm:
                        color = '#0000ff';
                        break;
                    case EnumMapToolType.CircleGeoFenceInOutAlarm:
                        color = '#00fa98';
                        break;
                }
                var ss = Math.sqrt(Math.pow(latlng.lat() - msgmap._circleGeoFenceCenter.lat(), 2) + Math.pow(latlng.lng() - msgmap._circleGeoFenceCenter.lng(), 2));
                msgmap._circleEndLatLng = latlng;
                msgmap.drawCircleGeoFence(msgmap._circleGeoFenceCenter.lat(), msgmap._circleGeoFenceCenter.lng(), ss, color, 5, 0.2);
            }
        }
    });

    this.translateRecordToTrackerInfo = function (record) {

        var sssid = record.get("sssid");
        var devicename = record.get("devicename");
        var devicetype = record.get("devicetype");
        var gpsavailable = record.get("gpsavailable");
        var latitude = record.get("latitude");
        var longitude = record.get("longitude");
        var gpstime = record.get("gpstime");
        var receivedtime = record.get("receivedtime");
        var direction = record.get("direction");
        var speed = record.get("speed");
        var altitude = record.get("altitude");
        var devicestate = record.get("devicestate");
        var address = record.get("address");
        var alarminfo = record.get("alarminfo");
        var baseid = record.get("baseid");
        var hasgsmlocation = record.get("hasgsmlocation");
        var gsmlatitude = record.get("gsmlatitude");
        var gsmlongitude = record.get("gsmlongitude");
        var gsmaccuracy = record.get("gsmaccuracy");
        var iconname = record.get("iconname");
        var alarmlatitude = record.get("alarmlatitude");
        var alarmlongitude = record.get("alarmlongitude");
        var alarmspeed = record.get("alarmspeed");
        var lastalarmtime = record.get("lastalarmtime");
        var lastgeofencename = record.get("lastgeofencename");
        var alarmcustomText = record.get("alarmcustomText");
        var gsm = null;
        if (hasgsmlocation && gsmaccuracy > 0) {
            gsm = new GSMInfo(gsmlatitude, gsmlongitude, 0, gsmaccuracy, "");
        }
        var tinfo = new TrackerInfo(sssid, devicename, devicetype, gpsavailable, longitude, latitude, gpstime, receivedtime, direction, speed, altitude, devicestate, address, alarminfo, gsm, null, null, null, iconname, alarmlatitude, alarmlongitude, alarmspeed, lastalarmtime, lastgeofencename, alarmcustomText);
        return tinfo;
    };

    // google map china region revise
    this.reviseAllOverlay = function () {
        this.map.setCenter(this.realLatLngToMapLatLng(this.map.getCenter()));
        var i;
        for (i = 0; i < this._vehicleOverlayerArray.length; i++) {
            var mm = this._vehicleOverlayerArray[i];
            mm.setLatLng(this.realLatLngToMapLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._labelOverlayerArray.length; i++) {
            var mm = this._labelOverlayerArray[i];
            mm.setLatLng(this.realLatLngToMapLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._realtimeOverlayArray.length; i++) {
            var mm = this._realtimeOverlayArray[i];
            mm.setLatLng(this.realLatLngToMapLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._historyOverlayArray.length; i++) {
            var mm = this._historyOverlayArray[i];
            mm.setLatLng(this.realLatLngToMapLatLng(mm.getLatLng()));
        }

        if (this._findOutLocationOverlay != null) {
            var mm = this._findOutLocationOverlay;
            mm.setLatLng(this.realLatLngToMapLatLng(mm.getLatLng()));
        }
        if (this._realtimeTrackingLine != null) {
            if (this._realtimeTrackingLine.getVertexCount() > 0) {
                var pts = [];
                var i;
                for (i = 0; i < this._realtimeTrackingLine.getVertexCount(); i++) {
                    var pt = this.realLatLngToMapLatLng(this._realtimeTrackingLine.getVertex(i));
                    pts.push(pt);
                }
                var tmpline = new GPolyline(pts, "#ff0000", 2);
                this.map.removeOverlay(this._realtimeTrackingLine);
                this._realtimeTrackingLine = tmpline;
                this.map.addOverlay(this._realtimeTrackingLine);
            }
        }
        if (this._historyLine != null) {
            if (this._historyLine.getVertexCount() > 0) {
                var pts = [];
                var i;
                for (i = 0; i < this._historyLine.getVertexCount(); i++) {
                    var pt = this.realLatLngToMapLatLng(this._historyLine.getVertex(i));
                    pts.push(pt);
                }
                var tmpline = new GPolyline(pts, "#ff0000", 2);
                this.map.removeOverlay(this._historyLine);
                this._historyLine = tmpline;
                this.map.addOverlay(this._historyLine);
            }
        }
    };

    this.removeTrackerInfo = function (trackerinfo) {
        var i;
        var alreadyhas = false;
        var index = -1;
        for (i = 0; i < this._trackerinfoLastArray.length; i++) {
            var tmptrackerinfo = this._trackerinfoLastArray[i];
            if (tmptrackerinfo.deviceid == trackerinfo.deviceid) {
                //delete last status icon before
                tmptrackerinfo.marker.closeExtInfoWindow();
                this.map.removeOverlay(tmptrackerinfo.marker);

                this.map.removeOverlay(tmptrackerinfo.label);
                if (this.meiEarth && this.earthState == EnumEarthState.Done)
                    this.meiEarth.RemoveMarker(tmptrackerinfo.placeMarker);
                this._labelOverlayerArray.remove(tmptrackerinfo.label);
                this._vehicleOverlayerArray.remove(tmptrackerinfo.marker);
                index = i;
                alreadyhas = true;
                break;
            }
        }
        if (alreadyhas) {
            delete this._trackerinfoLastArray[index].marker;
            delete this._trackerinfoLastArray[index].label;
            delete this._trackerinfoLastArray[index].placeMarker;
            this._trackerinfoLastArray.remove(this._trackerinfoLastArray[index]);
        }
    };

    //google map china region unrevise
    this.unReviseAllOverlay = function () {
        this.map.setCenter(this.mapLatLngToRealLatLng(this.map.getCenter()));
        var i;
        for (i = 0; i < this._vehicleOverlayerArray.length; i++) {
            var mm = this._vehicleOverlayerArray[i];
            mm.setLatLng(this.mapLatLngToRealLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._labelOverlayerArray.length; i++) {
            var mm = this._labelOverlayerArray[i];
            mm.setLatLng(this.mapLatLngToRealLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._realtimeOverlayArray.length; i++) {
            var mm = this._realtimeOverlayArray[i];
            mm.setLatLng(this.mapLatLngToRealLatLng(mm.getLatLng()));
        }
        for (i = 0; i < this._historyOverlayArray.length; i++) {
            var mm = this._historyOverlayArray[i];
            mm.setLatLng(this.mapLatLngToRealLatLng(mm.getLatLng()));
        }

        if (this._findOutLocationOverlay != null) {
            var mm = this._findOutLocationOverlay;
            mm.setLatLng(this.mapLatLngToRealLatLng(mm.getLatLng()));
        }
        if (this._realtimeTrackingLine != null) {
            if (this._realtimeTrackingLine.getVertexCount() > 0) {
                var pts = [];
                var i;
                for (i = 0; i < this._realtimeTrackingLine.getVertexCount(); i++) {
                    var pt = this.mapLatLngToRealLatLng(this._realtimeTrackingLine.getVertex(i));
                    pts.push(pt);
                }
                var tmpline = new GPolyline(pts, "#ff0000", 2);
                this.map.removeOverlay(this._realtimeTrackingLine);
                this._realtimeTrackingLine = tmpline;
                this.map.addOverlay(this._realtimeTrackingLine);
            }
        }
        if (this._historyLine != null) {
            if (this._historyLine.getVertexCount() > 0) {
                var pts = [];
                var i;
                for (i = 0; i < this._historyLine.getVertexCount(); i++) {
                    var pt = this.mapLatLngToRealLatLng(this._historyLine.getVertex(i));
                    pts.push(pt);
                }
                var tmpline = new GPolyline(pts, "#ff0000", 2);
                this.map.removeOverlay(this._historyLine);
                this._historyLine = tmpline;
                this.map.addOverlay(this._historyLine);
            }
        }
    };

    //gps real latlng to google map latlng,(china has revise)
    this.realLatLngToMapLatLng = function (latlng, noassertchina) {
        if (_mapurl == "maps.google.com") {
            if (this.map.getCurrentMapType() == G_NORMAL_MAP || this.map.getCurrentMapType() == G_OPENSTREET_MAP) {
                //satillite map don't need offset,other map all need offset
                if (noassertchina)
                    return reviseLatLng(latlng);
                else
                    return reviseRealLatLngToMap(latlng);
            }
            else
                return latlng;
        }
        else if (_mapurl == "ditu.google.com") {
            //all map need offset
            if (noassertchina)
                return reviseLatLng(latlng);
            else
                return reviseRealLatLngToMap(latlng);
        }
        else {
            if (noassertchina)
                return reviseLatLng(latlng);
            else
                return reviseRealLatLngToMap(latlng);
        }
    };

    //map latlng to real latlng
    this.mapLatLngToRealLatLng = function (latlng) {
        return unreviseMapLatLng(latlng);
    };

    //show new tracker in map
    this.showNewTrackerInfoOnMap = function (tinfo) {
        var pt = new GLatLng(tinfo.latitude, tinfo.longitude);
        if (tinfo.gsminfo != null) {
            pt = new GLatLng(tinfo.gsminfo.latitude, tinfo.gsminfo.longitude);
        }
        var alarmexp = (hasEmergencyAlarm(tinfo.alarminfo) ? getAlarmStringFromAlarmType(tinfo.alarminfo) : '');
        if (tinfo.alarminfo == "10010" || tinfo.alarminfo == "10011") {
            alarmexp += "(" + tinfo.lastgeofencename + ")";
        }
        if (tinfo.alarmcustomText != null)
            alarmexp = tinfo.alarmcustomText;
       
        var labelString = tinfo.devicename + ' ' + tinfo.speed + speedstr + ' ' + alarmexp + ' ' + tinfo.gpstime;
        if (this.meiEarth) {
            tinfo.setPlaceMarker(this.meiEarth.CreatePlaceMarker(pt, tinfo, labelString));
        }

        pt = this.realLatLngToMapLatLng(pt);
        tinfo.setLabel(createTLabel(pt, tinfo.devicename, tinfo.speed + speedstr, alarmexp, tinfo.gpstime));
        tinfo.setMarker(createMarker(pt, tinfo));
        this.drawNewTrackerInfo(tinfo);
    };

    // draw new tracker function
    this.drawNewTrackerInfo = function (trackerinfo) {
        var i;
        var alreadyhas = false;
        var index = -1;
        for (i = 0; i < this._trackerinfoLastArray.length; i++) {
            var tmptrackerinfo = this._trackerinfoLastArray[i];
            if (tmptrackerinfo.deviceid == trackerinfo.deviceid) {
                //delete last status icon before
                tmptrackerinfo.marker.closeExtInfoWindow();
                this.map.removeOverlay(tmptrackerinfo.marker);
                this.map.removeOverlay(tmptrackerinfo.label);
                if (this.meiEarth && this.earthState == EnumEarthState.Done)
                    this.meiEarth.RemoveMarker(tmptrackerinfo.placeMarker);
                this._labelOverlayerArray.remove(tmptrackerinfo.label);
                this._vehicleOverlayerArray.remove(tmptrackerinfo.marker);
                index = i;
                alreadyhas = true;
                break;
            }
        }
        if (alreadyhas) {
            delete this._trackerinfoLastArray[index].marker;
            delete this._trackerinfoLastArray[index].label;
            delete this._trackerinfoLastArray[index].placeMarker;
            this._trackerinfoLastArray.remove(this._trackerinfoLastArray[index]);
        }
        this.map.addOverlay(trackerinfo.marker);
        this._vehicleOverlayerArray.push(trackerinfo.marker);
        //this.map.addTLabel(trackerinfo.label);
        this.map.addOverlay(trackerinfo.label);
        this._labelOverlayerArray.push(trackerinfo.label);
        this._trackerinfoLastArray.push(trackerinfo);
        if (this.meiEarth) {
            if (trackerinfo.placeMarker)
                this.meiEarth.AddMarker(trackerinfo.placeMarker);
            this.meiEarth.ClearAllOfEarthMarker();
        }
    };

    this.changeTool = function (tool) {
        this._maptooltype = tool;
        switch (tool) {
            case EnumMapToolType.GeoFenceInAlarm:
            case EnumMapToolType.GeoFenceOutAlarm:
            case EnumMapToolType.CircleGeoFenceInAlarm:
            case EnumMapToolType.CircleGeoFenceOutAlarm:
            case EnumMapToolType.CircleGeoFenceInOutAlarm:
                panelmap.baseCls = 'dragzoom';
                break;
            case EnumMapToolType.Pan:
                panelmap.baseCls = 'pan';
                break;
            case EnumMapToolType.AddPOI:
                panelmap.baseCls = 'click';
                break;
            default:
                panelmap.baseCls = 'pan';
                break;
        }
    };

    this.maponclick = function (overlay, pt) {
        if (this._isdragging) {
            switch (this._maptooltype) {
                case EnumMapToolType.GeoFenceInAlarm:
                case EnumMapToolType.GeoFenceOutAlarm:
                    this._isdragging = false;
                    if (this._dragRectangle != null)
                        this.map.removeOverlay(this._dragRectangle);
                    if (this.FnGeoFenceCallBack != null) {
                        var ptbegin;
                        var ptend;
                        if (this.map.getCurrentMapType() == G_NORMAL_MAP || this.map.getCurrentMapType() == G_CHINA_MAP || this.map.getCurrentMapType() == G_OPENSTREET_MAP) {
                            ptbegin = this.mapLatLngToRealLatLng(this._dragrectbeginlatlng);
                            ptend = this.mapLatLngToRealLatLng(this._dragrectendlatlng);
                        }
                        else {
                            if (this.map.getCurrentMapType() == G_SATELLITE_MAP) {
                                if (_mapurl == "maps.google.com") {
                                    ptbegin = this._dragrectbeginlatlng;
                                    ptend = this._dragrectendlatlng;
                                }
                                else if (_mapurl == "ditu.google.com") {
                                    ptbegin = this.mapLatLngToRealLatLng(this._dragrectbeginlatlng);
                                    ptend = this.mapLatLngToRealLatLng(this._dragrectendlatlng);
                                }
                            }

                        }
                        this.FnGeoFenceCallBack(ptbegin.lat(), ptbegin.lng(), ptend.lat(), ptend.lng());
                    }
                    this.changeTool(EnumMapToolType.Pan);
                    this.map.enableDragging();
                    break;
                case EnumMapToolType.CircleGeoFenceInAlarm:
                case EnumMapToolType.CircleGeoFenceInOutAlarm:
                case EnumMapToolType.CircleGeoFenceOutAlarm:
                    this._isdragging = false;
                    if (this._preRadiusGeoFenceOverlay != null)
                        this.map.removeOverlay(this._preRadiusGeoFenceOverlay);
                    if (this.map.getCurrentMapType() == G_NORMAL_MAP || this.map.getCurrentMapType() == G_CHINA_MAP || this.map.getCurrentMapType() == G_OPENSTREET_MAP) {
                        ptbegin = this.mapLatLngToRealLatLng(this._circleGeoFenceCenter);
                        ptend = this.mapLatLngToRealLatLng(this._circleEndLatLng);
                    }
                    else {

                        if (_mapurl == "maps.google.com") {
                            ptbegin = this._circleGeoFenceCenter;
                            ptend = this._circleEndLatLng;
                        }
                        else if (_mapurl == "ditu.google.com") {
                            ptbegin = this.mapLatLngToRealLatLng(this._circleGeoFenceCenter);
                            ptend = this.mapLatLngToRealLatLng(this._circleEndLatLng);
                        }

                    }
                    var distance = ptbegin.distanceFrom(ptend);
                    if (this.FnCircleGeoFenceCallBack != null)
                        this.FnCircleGeoFenceCallBack(ptbegin.lat(), ptbegin.lng(), distance);
                    this.changeTool(EnumMapToolType.Pan);
                    this.map.enableDragging();
                    break;
                default:
                    break;
            }
        }
        else {
            if (pt != null) {
                this._dragrectbeginlatlng = pt;
                switch (this._maptooltype) {
                    case EnumMapToolType.GeoFenceInAlarm:
                    case EnumMapToolType.GeoFenceOutAlarm:
                        this._isdragging = true;
                        break;
                    case EnumMapToolType.AddPOI:
                        this.drawAddPOI(pt.lat(), pt.lng(), 0, this._submitcap, this._cancelcap, "", "");
                        break;
                    case EnumMapToolType.CircleGeoFenceInAlarm:
                    case EnumMapToolType.CircleGeoFenceInOutAlarm:
                    case EnumMapToolType.CircleGeoFenceOutAlarm:
                        this._circleGeoFenceCenter = pt;
                        this._isdragging = true;
                        break;
                    case EnumMapToolType.DrawDefinedRoute:
                        this._routeTempPoint = pt;
                        pt = pt.toUrlValue(6);
                        if (this._waypoints.length == 0) { // no waypoints exist yet - map was clicked for start of the route
                            this.GDir1.loadFromWaypoints([pt, pt], { getPolyline: true }); // get directions from that point to itself to snap it to street

                        }
                        else {
                            // map was clicked for additional waypoint
                            if (this._finishDrawRoute == false) {
                                var myPoint = this._waypoints[this._waypoints.length - 1].getPoint().toUrlValue(6);
                                this.GDir1.loadFromWaypoints([myPoint, pt], { getPolyline: true }); //get directions from last waypoint to clicked point
                                this._maptooltype = EnumMapToolType.Pan;
                                this._finishDrawRoute = true;
                            }
                        }
                        break;
                    case EnumMapToolType.BeginEditMovePOI:
                        this.changeTool(EnumMapToolType.Pan);
                        break;
                    case EnumMapToolType.StreetMode:
                        this._gsvPanorama.setLocationAndPOV(pt);
                        break;
                    case EnumMapToolType.DrawPolygonGeoFenceInAlarm:
                    case EnumMapToolType.DrawPolygonGeoFenceInOutAlarm:
                    case EnumMapToolType.DrawPolygonGeoFenceOutAlarm:
                        this.drawNewPolygonFence(pt);
                        break;
                }
            }
        }

    };



    function createTLabel(point, username, speed, alarminfo, location) {
        var color = '#000';
        if (alarminfo.length > 0)
            color = '#FF0000';
        var content1 = '<div style="padding: 20px 0px 4px 20px; "><div style="background-color: #f2efe9; border: 1px solid #000; padding: 2px; font-family: arial; font-size: 11px; color: ' + color + '; text-decoration: none;"><nobr>' + username + ' ' + speed + ' ' + alarminfo + ' ' + location + '</nobr></div></div>';
        var label1 = new TLabel(point);
        label1.setContent(content1);
        return label1;
    }

    function getDefaultImageUrl(trackerinfo) {
        var s = trackerinfo.devicetype;
        var direction = parseFloat(trackerinfo.direction);
        var url = "blue.gif";

        if (s == 0 || s == 1 || s == 2 || s == 5 || s == 7 || s == 12) {
            url = "man.gif";
        }
        else {
            var baseImagePath;
            if (trackerinfo.gsminfo != null) {
                url = "car.gif";
            }
            else {
                baseImagePath = "car_";
                if (direction >= 337.5 || direction < 22.5)
                    url = baseImagePath + "n.png";
                else if (direction >= 22.5 && direction < 67.5)
                    url = baseImagePath + "ne.png";
                else if (direction >= 67.5 && direction < 112.5)
                    url = baseImagePath + "e.png";
                else if (direction >= 112.5 && direction < 157.5)
                    url = baseImagePath + "se.png";
                else if (direction >= 157.5 && direction < 202.5)
                    url = baseImagePath + "s.png";
                else if (direction >= 202.5 && direction < 247.5)
                    url = baseImagePath + "sw.png";
                else if (direction >= 247.5 && direction < 292.5)
                    url = baseImagePath + "w.png";
                else if (direction >= 292.5 && direction < 337.5)
                    url = baseImagePath + "nw.png";
            }
        }
        return url;
    }

    //create new Marker
    function createMarker(point, trackerinfo) {
        var icon = new GIcon(baseIcon);
        icon.iconSize = new GSize(40, 40);
        icon.infoWindowAnchor = new GPoint(44, 30);
        var direction = trackerinfo.direction;
        var speedkmh = parseInt(trackerinfo.speed);
        var s = trackerinfo.devicetype;
        var imgsrc = trackerinfo.iconname != "" ? "images/trackericon/" + trackerinfo.iconname + "_" : "images/trackericon/" + getDefaultImageUrl(trackerinfo);

        var marker;
        if (trackerinfo.iconname != "") {
            if (direction == "East") {
                imgsrc += "n.png";
            }
            if (direction == "North") {
                imgsrc += "n.png";
            }
            if (direction == "South") {
                imgsrc += "n.png";
            }
            if (direction == "West") {
                imgsrc += "n.png";
            }
            else {
                imgsrc = "images/trackericon/" + trackerinfo.iconname;
                imgsrc += ".png";
            }

        }
        //var imgsrc ="images/0002.gif";//测试动画gif
        if (trackerinfo.gsminfo != null) {
            imgsrc = 'images/trackericon/' + (trackerinfo.iconname != "" ? trackerinfo.iconname + '.gif' : getDefaultImageUrl(trackerinfo)); //PNG 有阴影，这里使用GIF
            marker = new ExLBSDevice(point, trackerinfo.gsminfo.accuracy, imgsrc);
        }
        else {
            icon.image = imgsrc;
            marker = new GMarker(point, icon, true);
            marker.id = trackerinfo.deviceid;
        }
        if (hasEmergencyAlarm(trackerinfo.alarminfo) && isOpenExtentFn) {
            var content = "<div>" +
            _ReportResources_DeviceName + ":" + trackerinfo.devicename + "<br/>" +
            _TrackerMain_Alarm + ":" + getAlarmStringFromAlarmType(trackerinfo.alarminfo) + "<br/>" +
            _Alarm_AlarmTime + ":" + trackerinfo.lastalarmtime + "<br/>" +
            _TrackerMain_Speed + ":" + trackerinfo.alarmspeed + speedstr + "<br/>" + _Alarm_Header_Location + ":";
            _msgmap.geoCoder(trackerinfo.alarmlatitude, trackerinfo.alarmlongitude, function (address) {
                if (address.length > 0)
                    content += address + "<br/></div>";
                else
                    content += trackerinfo.alarmlongitude + "," + trackerinfo.alarmlatitude + "<br/></div>";
                marker.ExtInfoWindow(gmap, marker.id + '--extInfoWindow_coolBlues', content, { beakOffset: 1 }, function () {
                    submitAndCancelAlarm(trackerinfo.deviceid);
                }
            );
            }, true);

        }
        return marker;

    }
    this.createPointMarker = function (point) {
        var icon = new GIcon(baseIcon);
        icon.iconAnchor = new GPoint(5, 5);
        icon.iconSize = new GSize(10, 10);
        icon.image = "images/node.gif";
        var marker = new GMarker(point, icon);
        return marker;
    };
    this.createSimpleMarker = function (point) {
        var icon = new GIcon(baseIcon);
        icon.iconAnchor = new GPoint(16, 32);
        icon.image = "images/blue.png";
        var marker = new GMarker(point, icon);
        return marker;
    };

    this.createStoppedMarker = function (point, win_html) {
        var icon = new GIcon(baseIcon);
        icon.iconAnchor = new GPoint(16, 32);
        icon.image = "images/red-stop.png";
        var marker = new GMarker(point, icon);
        if (win_html) {
            GEvent.addListener(marker, "click", function (latlng) {
                _msgmap.geoCoder(point.lat(), point.lng(), function (address) {
                    var content = "";
                    if (address.length > 0)
                        content = address;
                    else
                        content = _msgmap._latitude + ":" + point.lat().toString() + " " + _msgmap._longitude + ":" + point.lng().toString();
                    marker.openInfoWindowHtml(win_html + address);
                }, true);

            });
        }
        return marker;
    };

    this.createTrackBeginEndMarker = function (point, begin, win_html) {
        var icon = new GIcon(baseIcon);
        icon.iconAnchor = new GPoint(16, 32);
        if (begin)
            icon.image = "images/icon_greenA.png";
        else
            icon.image = "images/icon_greenB.png";
        var marker = new GMarker(point, icon);
        if (win_html) {
            GEvent.addListener(marker, "click", function (latlng) {
                _msgmap.geoCoder(latlng.lat(), latlng.lng(), function (address) {
                    if (address.length > 0)
                        win_html += address;
                    else
                        win_html += _msgmap._latitude + ":" + latlng.lat().toString() + " " + _msgmap._longitude + ":" + latlng.lng().toString();
                    marker.openInfoWindowHtml(win_html);
                }, true);

            });
        }
        return marker;
    };

    this.createAlarmLabel = function (point, username, speed, alarminfo, location) {
        var color = '#000';
        if (alarminfo.length > 0)
            color = 'red';
        var content1 = '<div style="padding: 20px 0px 4px 20px; "><div style="background-color: #f2efe9; border: 1px solid #000; padding: 2px; font-family: arial; font-size: 11px; color:" ' + color + '"; text-decoration: none;"><nobr>' + username + ' ' + speed + ' ' + alarminfo + ' ' + location + '</nobr></div></div>';
        var label1 = new TLabel(point);
        label1.setContent(content1);
        return label1;
    };

    this.createAlarmMarker = function (point, trackerinfo) {
        var icon = new GIcon();
        icon.iconSize = new GSize(32, 32);
        icon.image = "images/caution.png";
        icon.iconAnchor = new GPoint(6, 20);
        icon.infoWindowAnchor = new GPoint(5, 1);
        var direction = parseFloat(trackerinfo.direction);
        var speedkmh = parseInt(trackerinfo.speed);
        var marker;
        if (trackerinfo.gsminfo != null) {
            marker = new ExLBSDevice(point, trackerinfo.gsminfo.accuracy, "images/caution.gif");
        }
        else
            marker = new GMarker(point, icon);
        return marker;
    };


    this.createTrackMarker = function (point, directionString, win_html) {
        var icon = new GIcon(baseIcon);
        icon.iconAnchor = new GPoint(16, 32);
        var direction = directionString;
        var baseImagePath;
        baseImagePath = "images/blue_";
        icon.image = baseImagePath;
        var tmarker = new GMarker(point, icon);
        if (win_html) {
            GEvent.addListener(tmarker, "click", function (latlng) {
                _msgmap.geoCoder(latlng.lat(), latlng.lng(), function (address) {
                    if (address.length > 0)
                        win_html += address;
                    else
                        win_html += _msgmap._latitude + ":" + latlng.lat().toString() + " " + _msgmap._longitude + ":" + latlng.lng().toString();
                    tmarker.openInfoWindowHtml(win_html);
                }, true);

            });
        }
        //tmarker.id = Math.random().toString();
        if (direction == "East") {
            icon.image = baseImagePath + "e.png";
        }
        if (direction == "North") {
            icon.image = baseImagePath + "n.png";
        }
        if (direction == "South") {
            icon.image = baseImagePath + "s.png";
        }
        if (direction == "West") {
            icon.image = baseImagePath + "w.png";
        }
        return tmarker;
    };

    if (fncallback != null)
        fncallback();
};

MSGMap.prototype = {

    //var gmap = new GMap2();
    checkResize: function() {
        this.map.checkResize();
    }

    , setCenter: function(glntlng, zoom, type) {
        var pt = this.realLatLngToMapLatLng(glntlng); //--trans latlng-
        this.map.setCenter(pt, zoom, type);
    }

    , setCenterbyLatLng: function(lat, lng, zoom, type) {
        var pt = this.realLatLngToMapLatLng(new GLatLng(lat, lng)); //--trans latlng-
        this.map.setCenter(pt, zoom, type);
    }

    , drawSimplePointByXY: function(lat, lng, bolcenter, zoomLevel) {
        var pt = new GLatLng(lat, lng);
        pt = this.realLatLngToMapLatLng(pt);
        var mm = this.createSimpleMarker(pt);
        this.map.addOverlay(mm);
        if (bolcenter)
            this.map.setCenter(pt, zoomLevel);
    }

    , drawFromStore: function(pstore, bolcenter, zoomLevel) {
        var count = pstore.getCount();
        var i;
        if (this._bolfirsttimeload) {
            //first login give bounds to browser map
            if (this._bounds != null)
                this._bounds = null;
            this._bounds = new GLatLngBounds();
            if (count == 1) {
                var record = pstore.getAt(0);
                var tinfo = this.translateRecordToTrackerInfo(record);
                var pt;
                if (tinfo.gsminfo != null)
                    pt = new GLatLng(tinfo.gsminfo.latitude, tinfo.gsminfo.longitude);
                else
                    pt = new GLatLng(tinfo.latitude, tinfo.longitude);
                pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
                this._bounds.extend(pt);
                this.map.setCenter(pt, 13);

            }
            else if (count > 1) {
                for (i = 0; i < count; i++) {
                    var record = pstore.getAt(i);
                    var tinfo = this.translateRecordToTrackerInfo(record);
                    var pt;
                    if (tinfo.gsminfo != null)
                        pt = new GLatLng(tinfo.gsminfo.latitude, tinfo.gsminfo.longitude);
                    else
                        pt = new GLatLng(tinfo.latitude, tinfo.longitude);
                    pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
                    this._bounds.extend(pt);
                }
                this.map.setCenter(this._bounds.getCenter(), this.map.getBoundsZoomLevel(this._bounds));
            }
            this._bolfirsttimeload = false;
        }
        var lasttinfo;
        for (i = 0; i < count; i++) {
            var record = pstore.getAt(i);
            var tinfo = this.translateRecordToTrackerInfo(record);
            lasttinfo = tinfo;
            this.showNewTrackerInfoOnMap(tinfo);
        }

        if (bolcenter && (lasttinfo != null)) {
            var pt = new GLatLng(lasttinfo.latitude, lasttinfo.longitude);
            if (lasttinfo.gsminfo != null)
                pt = new GLatLng(lasttinfo.gsminfo.latitude, lasttinfo.gsminfo.longitude);
            if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
                pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
            }

            this.map.setCenter(pt);
            if (zoomLevel)
                this.map.setZoom(zoomLevel);
        }

    }

    // here fncallback must be a function with 1 string parameters
    , geoCoder: function(lati, longi, fncallback, ismaplatlng) {
        this._geocoder.reset();
        var latlng = new GLatLng(lati, longi);
        if (ismaplatlng) {
        }
        else
            latlng = this.realLatLngToMapLatLng(latlng);
        this._geocoder.getLocations(latlng, function(response) {
            if (response.Status.code == 200) {
                var place = response.Placemark[0];
                var address = place.address;
                if (fncallback != null)
                    fncallback(address, 1);
            }
            else {
                fncallback("");
            }
        });
    }

    , beginDrawGeoFence: function(inout) {
        if (inout == 0)
            this.changeTool(EnumMapToolType.GeoFenceOutAlarm);
        else if (inout == 1)
            this.changeTool(EnumMapToolType.GeoFenceInAlarm);
    }

    , beginDrawCircleGeoFence: function(inout) {
        if (inout == 0)
            this.changeTool(EnumMapToolType.CircleGeoFenceOutAlarm);
        else if (inout == 1)
            this.changeTool(EnumMapToolType.CircleGeoFenceInAlarm);
        else
            this.changeTool(EnumMapToolType.CircleGeoFenceInOutAlarm);
    }

    , realtimeTracking: function(record, gpsTimeCap, speedCap) {
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            var tinfo = this.translateRecordToTrackerInfo(record);
            if (tinfo) {
                var pt = new GLatLng(tinfo.latitude, tinfo.longitude);
                pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
                var isGPSFlowingPoint = false; //is the point is gps flowing point

                if (this._realtimeTrackingLine == null) {
                    this._realtimeTrackingLine = new GPolyline([pt], "#ff0000", 2);
                    this.map.addOverlay(this._realtimeTrackingLine);
                }
                else {
                    var lastpt = this._realtimeTrackingLine.getVertex(0);
                    if (pt.distanceFrom(lastpt) < 15) {
                        this._realtimeTrackingLine.deleteVertex(0);
                        isGPSFlowingPoint = true;
                    }
                    this._realtimeTrackingLine.insertVertex(0, pt);
                }
                if (!isGPSFlowingPoint) {
                    tinfo.direction = (tinfo.direction != null ? tinfo.direction : "0");
                    var marker = this.createTrackMarker(pt, tinfo.direction);
                    GEvent.addListener(marker, "mouseover", function() {
                        var WIN_HTML;
                        var timetext = gpsTimeCap + ':' + tinfo.gpstime + '<BR/>';
                        var speedtext = speedCap + ':' + tinfo.speed + '' + speedstr + '<BR/>';
                        WIN_HTML = timetext + speedtext;
                        marker.openInfoWindowHtml(WIN_HTML);
                    });
                    if (this._realtimeOverlayArray.length < 15) {
                        this.map.addOverlay(marker);
                        this._realtimeOverlayArray.push(marker);
                    }
                    else {
                        this.map.removeOverlay(this._realtimeOverlayArray[0]);
                        this._realtimeOverlayArray.remove(this._realtimeOverlayArray[0]);
                        this.map.addOverlay(marker);
                        this._realtimeOverlayArray.push(marker);
                    }
                }
                else {
                    var marker = this._realtimeOverlayArray[this._realtimeOverlayArray.length - 1];
                    marker.setLatLng(pt);
                    GEvent.addListener(marker, "mouseover", function() {
                        var WIN_HTML;
                        var timetext = gpsTimeCap + ':' + tinfo.gpstime + '<BR/>';
                        var speedtext = speedCap + ':' + tinfo.speed + speedstr + '<BR/>';
                        WIN_HTML = timetext + speedtext;
                        marker.openInfoWindowHtml(WIN_HTML);
                    });
                }
                if (!this.map.getBounds().containsLatLng(pt))
                    this.map.panTo(pt);
            }
        }
        else {
            if (this.earthState == EnumEarthState.Unknown)
                return;
            var tinfo = this.translateRecordToTrackerInfo(record);
            if (tinfo) {
                var pt = new GLatLng(tinfo.latitude, tinfo.longitude);
                var distance = 0;
                var duration = 0;
                if (this.meiEarth.realtimepoints.length > 0) {
                    distance = pt.distanceFrom(this.meiEarth.realtimepoints[this.meiEarth.realtimepoints.length - 1].loc);
                    duration = distance / (this.meiEarth.realtimepoints[this.meiEarth.realtimepoints.length - 1].speed * 1000 / 3600);
                }
                this.meiEarth.realtimepoints.push({ loc: pt, distance: distance, duration: duration, speed: tinfo.speed });
                var isGPSFlowingPoint = false; //is the point is gps flowing point
                var coors = null;
                if (this.meiEarth.realtimetrackingline == null) {
                    this.meiEarth.realtimetrackingline = this.meiEarth.CreateHistoryLine([pt, pt], this.meiEarth);
                    this.meiEarth.AddMarker(this.meiEarth.realtimetrackingline);
                    coors = this.meiEarth.realtimetrackingline.getGeometry().getCoordinates();
                }
                else {
                    coors = this.meiEarth.realtimetrackingline.getGeometry().getCoordinates();
                    var lastpt = coors[0];
                    coors.pushLatLngAlt(pt.lat(), pt.lng(), 0);
                }
                if (!isGPSFlowingPoint) {
                    tinfo.direction = (tinfo.direction != null ? tinfo.direction : "0");
                    var WIN_HTML;
                    var timetext = gpsTimeCap + ':' + tinfo.gpstime + '<BR/>';
                    var speedtext = speedCap + ':' + tinfo.speed + speedstr + '<BR/>';
                    WIN_HTML = timetext + speedtext;
                    var marker = this.meiEarth.CreateEarthTrackerMarker(pt, tinfo.direction, tinfo.gpstime, WIN_HTML);

                    if (coors.length >= 15) {
                        this.meiEarth.RemoveMarker(this.meiEarth.realtimeoverlayarray[0]);
                        this.realtimeoverlayarray.remove(this.meiEarth.realtimeoverlayarray[0]);
                    }
                    this.meiEarth.AddMarker(marker);
                    this.meiEarth.realtimeoverlayarray.push(marker);
                    this.meiEarth.FlyToLatLng(pt, 100);
                    if (coors.getLength() > 2) {

                        var firstpoint = this.meiEarth.realtimepoints[this.meiEarth.realtimepoints.length - 2];
                        var secondpoint = this.meiEarth.realtimepoints[this.meiEarth.realtimepoints.length - 1];
                        var path = [];
                        path.push({ step: 0, loc: firstpoint.loc, name: "", distance: firstpoint.distance, duration: firstpoint.duration });
                        path.push({ step: 1, loc: secondpoint.loc, name: "", distance: secondpoint.distance, duration: secondpoint.duration });
                        this.meiEarth.RunDSCarInEarth(path);
                        this.meiEarth.FlyToLatLng(pt, distance);
                    }
                }
                else {
                    var marker = this.realtimeoverlayarray[this.realtimeoverlayarray.length - 1];
                    //marker.setLatLng(pt);
                }
            }

        }
    }

    , drawHistoryPoint: function(record) {
        var lati = record.get("latitude");
        var longi = record.get("longitude");
        var direction = record.get("direction");
        var hasgsmlocation = record.get("hasgsmlocation");
        var pt = new GLatLng(lati, longi);
        if (hasgsmlocation) {
            pt = new GLatLng(record.get("gsmlatitude"), record.get("gsmlongitude"));
        }
        if (this.meiEarth) {
            this.meiEarth.historypt = { point: pt, name: record.get("gpstime"), direction: direction };
            this.meiEarth.DrawHistoryPoint();
        }
        pt = this.realLatLngToMapLatLng(pt); //--trans latlng-

        var mm;
        var zoom = 14;
        if (hasgsmlocation) {
            var accuracy = record.get("gsmaccuracy");
            mm = new ExLBSDevice(pt, accuracy, "images/blue.gif");
            zoom = this.getZoomFromRadius(accuracy);
        }
        else
            mm = this.createTrackMarker(pt, direction);
        this.map.addOverlay(mm);
        if (this.map.getCurrentMapType() == G_SATELLITE_3D_MAP)
            this.map.setCenter(pt, zoom);
        else
            this.map.setCenter(this.mapLatLngToRealLatLng(pt), zoom);


    }

    , drawParkingPoint: function(record) {
        var lati = record.get("Latitude");
        var longi = record.get("Longitude");
        var pt = new GLatLng(lati, longi);
        pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
        var mm;
        var zoom = 14;
        mm = this.createTrackMarker(pt, 0);
        this.map.addOverlay(mm);
        this.map.setCenter(this.mapLatLngToRealLatLng(pt), zoom);
    }

    , drawSennorEventPoint: function(record) {
        var startlati = record.get("StartAddress").split(',')[1];
        var startlongi = record.get("StartAddress").split(',')[0];
        var overlati = record.get("OverAddress").split(',')[1];
        var overlongi = record.get("OverAddress").split(',')[0];
        var pt1 = new GLatLng(startlati, startlongi);
        var pt2 = new GLatLng(overlati, overlongi);
        pt1 = this.realLatLngToMapLatLng(pt1); //--trans latlng-
        pt2 = this.realLatLngToMapLatLng(pt2); //--trans latlng-
        var mm, mm1;
        var zoom = 14;
        mm = this.createTrackMarker(pt1, 0);
        mm1 = this.createTrackMarker(pt2, 0);
        this.map.addOverlay(mm);
        this.map.addOverlay(mm1);
        this.map.setCenter(pt1, zoom);

    }
    , getZoomFromRadius: function(accuracy) {
        if (accuracy < 2500)
            zoom = 15;
        else if (accuracy > 2500 && accuracy < 5000)
            zoom = 13;
        else
            zoom = 12;
        return zoom;
    }

    , drawAlarmPoint: function(trackerinfo) {
        var pt = new GLatLng(trackerinfo.latitude, trackerinfo.longitude);
        if (trackerinfo.gsminfo != null)
            pt = new GLatLng(trackerinfo.gsminfo.latitude, trackerinfo.gsminfo.longitude);
        if (this.meiEarth) {
            this.meiEarth.historypt = { point: pt, name: trackerinfo.devicename + "," + trackerinfo.speed + speedstr + "," + trackerinfo.alarminfo + "," + trackerinfo.gpstime + trackerinfo.address };
            this.meiEarth.DrawAlarmPoint();
        }
        pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
        trackerinfo.setLabel(this.createAlarmLabel(pt, trackerinfo.devicename, trackerinfo.speed + speedstr, trackerinfo.alarminfo, trackerinfo.gpstime + trackerinfo.address));
        trackerinfo.setMarker(this.createAlarmMarker(pt, trackerinfo));
        this.map.addOverlay(trackerinfo.marker);
        //this.map.addTLabel(trackerinfo.label);
        this.map.addOverlay(trackerinfo.label);
        var zoom = 14;
        if (trackerinfo.gsminfo != null)
            zoom = this.getZoomFromRadius(trackerinfo.gsminfo.accuracy);
        this.map.setCenter(pt, zoom);
    }

    , stopAnimate: function() {
        this._stopanimate = true;
        if (this.map.getCurrentMapType() == G_SATELLITE_3D_MAP) {
            this.meiEarth.DSCarPause();
        }

    }
    , startAnimate: function() {
        this._stopanimate = false;
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            this.showAnimate(this);
        }
        else {
            if (!this.meiEarth.DS_simulator)
                this.meiEarth.BeginRunCar();
            else
                this.meiEarth.DSCarContinue();
        }

    }
    , speedUpAnimate: function() {
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            this._animateinterval = this._animateinterval / 2;
        }
        else {
            this.meiEarth.DSCarFaster();
        }
    }
    , slowDownAnimate: function() {
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            this._animateinterval = this._animateinterval * 2;
        }
        else {
            this.meiEarth.DSCarSlower();
        }
    }
    , toStartPoint: function() {
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            var j;
            for (j = 0; j < this._historyOverlayArray.length; j++) {
                this.map.removeOverlay(this._historyOverlayArray[j]);
            }
            this._historyshowindex = 0;
            if (this._historyLine != null)
                this.map.removeOverlay(this._historyLine);
            var points = [];
            this._historyLine = new GPolyline(points, "#ff0000", 2);
            this.map.addOverlay(this._historyLine);
            this.map.setZoom(14);
            this.showAnimate(this);
        }
        else {
            this.meiEarth.DSCarGoFirstPoint();
        }
    }
    , toEndPoint: function() {
        if (this.map.getCurrentMapType() != G_SATELLITE_3D_MAP) {
            this.stopAnimate();
            this._historyshowindex = this._trackerhistoryinfoArray.length - 1;
            this.showAnimate(this);
        }
        else {
            this.meiEarth.DSCarGoLastPoint();
        }
    }
    , toInitAnimateForChangeMapType: function() {
        this.toStartPoint();
        this.stopAnimate();
    }
    , _showAnimate: function(obj) {
        return function() {
            obj.showAnimate(obj);
        }
    }
    , showAnimate: function(obj) {
        if (obj._historyshowindex < obj._trackerhistoryinfoArray.length && obj._stopanimate == false) {
            var vinfo = obj._trackerhistoryinfoArray[obj._historyshowindex];
            obj._historyshowindex++;
            pt = obj.realLatLngToMapLatLng(new GLatLng(vinfo.latitude, vinfo.longitude));
            var WIN_HTML;
            var timetext = obj._gpsTimeCap + ':' + vinfo.gpstime + '<BR/>';
            var speedtext = obj._speedCap + ':' + vinfo.speed + speedstr + '<BR/>';
            var latlngtext = _Alarm_Header_Latitude + "," + _Alarm_Header_Longitude + ":" + vinfo.latitude + "," + vinfo.longitude + "<br/>";
            var otherinfo = "";
            if (vinfo.otherinfo)
                otherinfo = vinfo.otherinfo + '<BR/>';
            WIN_HTML = timetext + latlngtext + speedtext + otherinfo;
            if (vinfo.stopped)
                WIN_HTML += obj._parkingTimeCap + ":" + vinfo.stoppedtime + '<BR/>';
            var mm;
            //            if (obj._historyshowindex == 1)
            //                mm = obj.createTrackBeginEndMarker(pt, true, WIN_HTML);
            //            else if (obj._historyshowindex == obj._trackerhistoryinfoArray.length)
            //                mm = obj.createTrackBeginEndMarker(pt, false, WIN_HTML);
            //            else 
            if (vinfo.stopped) {
                mm = obj.createStoppedMarker(pt, WIN_HTML);
            }
            else
                mm = obj.createTrackMarker(pt, vinfo.direction.toString(), WIN_HTML);

            obj.map.addOverlay(mm);
            obj._historyOverlayArray.push(mm);
            obj.map.panTo(pt);
            if (!obj._hidehistoryline)
                obj._historyLine.insertVertex(0, pt);
            obj._historyshowtimer = window.setTimeout(obj._showAnimate(obj), obj._animateinterval);
            if (obj._historyshowindex == obj._trackerhistoryinfoArray.length) {
                if (obj._historylineendfn != null)
                    obj._historylineendfn(obj); //call back
            }

        }
    }

    , drawAnimateHistoryLine: function(extdatastore, gpsTimeCap, speedCap, fnShowEndCallback, hideLine) {
        this._historylineendfn = fnShowEndCallback;
        this._hidehistoryline = (typeof (hideLine) != 'undefined' ? hideLine : false);
        this._gpsTimeCap = gpsTimeCap;
        this._speedCap = speedCap;
        //        if (this._historyLine != null) {
        //            this.map.removeOverlay(this._historyLine);
        //            this._historyLine == null;
        //        }
        //        var j;
        //        for (j = 0; j < this._historyOverlayArray.length; j++) {
        //            this.map.removeOverlay(this._historyOverlayArray[j]);
        //        }

        var i;

        for (i = 0; i < extdatastore.getCount(); i++) {
            var record = extdatastore.getAt(i);
            var lati = record.get("latitude");
            var longi = record.get("longitude");
            var otherLati = (i == extdatastore.getCount() - 1) ? parseFloat(extdatastore.getAt(i).get("latitude")) : parseFloat(extdatastore.getAt(i + 1).get("latitude"));
            var otherLongi = (i == extdatastore.getCount() - 1) ? parseFloat(extdatastore.getAt(i).get("longitude")) : parseFloat(extdatastore.getAt(i + 1).get("longitude"));
            var gpstime = record.get("gpstime");
            var direction = record.get("direction");
            var speed = record.get("speed");
            var otherinfo = record.get("otherinfo");
            var stopped = record.get("stopped");
            var stoppedtime = record.get("stoppedtime");
            var historyinfo = new TrackerInfo("", "", "", "", longi, lati, gpstime, "", direction, speed, "", "", "", "", "", otherinfo, stopped, stoppedtime);
            this._trackerhistoryinfoArray.push(historyinfo);
            var point = new GLatLng(lati, longi);
            var otherPoint = new GLatLng(otherLati, otherLongi);
            var distance = point.distanceFrom(otherPoint);
            //            if (this.meiEarth)
            this.History_points.push({ step: i, loc: point, name: gpstime + "," + speed, distance: distance, duration: 0 });

        }
        //this._historyshowindex = 0;
        //        if (this._historyLine != null)
        //            this.map.removeOverlay(this._historyLine);
        var points = [];
        if (this._historyLine == null && (!this._hidehistoryline)) {
            this._historyLine = new GPolyline(points, "#ff0000", 2);
            this.map.addOverlay(this._historyLine);
        }
        if (this._historyshowindex == 0)
            this.map.setCenter(new GLatLng(0, 0), 14);
        //this.map.setZoom(14);
        this.showAnimate(this);
    }

    , drawHistoryLine: function(extdatastore, gpsTimeCap, speedCap) {
        this._gpsTimeCap = gpsTimeCap;
        this._speedCap = speedCap;
        if (this._historyLine != null) {
            this.map.removeOverlay(this._historyLine);
            this._historyLine == null;
        }

        var j;
        for (j = 0; j < this._historyOverlayArray.length; j++) {
            this.map.removeOverlay(this._historyOverlayArray[j]);
        }
        this._historyOverlayArray.clear();

        var bounds = new GLatLngBounds();
        var points = new Array();
        var i;
        for (i = 0; i < extdatastore.getCount(); i++) {
            var record = extdatastore.getAt(i);
            var lati = record.get("latitude");
            var longi = record.get("longitude");
            var gpstime = record.get("gpstime");
            var direction = record.get("direction");
            var speed = record.get("speed");
            var pt = new GLatLng(lati, longi);
            pt = this.realLatLngToMapLatLng(pt); //--trans latlng-
            bounds.extend(pt);
            points.push(pt);
            if (i == 0) {
                var bmarker = this.createTrackBeginEndMarker(pt, true);
                GEvent.addListener(bmarker, "mouseover", function() {
                    var WIN_HTML;
                    var timetext = gpsTimeCap + ':' + gpstime + '<BR/>';
                    var speedtext = speedCap + ':' + speed + speedstr + '<BR/>';
                    WIN_HTML = timetext + speedtext;
                    bmarker.openInfoWindowHtml(WIN_HTML);
                });
                this.map.addOverlay(bmarker);
                this._historyOverlayArray.push(bmarker);
            }
            else if (i == extdatastore.getCount() - 1) {

                var emarker = this.createTrackBeginEndMarker(pt, false);
                this.map.addOverlay(emarker);
                this._historyOverlayArray.push(emarker);
            }
            else {
                if (i % 10 == 0) {
                    var marker = this.createTrackMarker(pt, direction);
                    this.map.addOverlay(marker);
                    this._historyOverlayArray.push(marker);
                }
            }
        }
        if (points.length > 0) {
            this._historyLine = new GPolyline(points, "#ff0000", 2);
            this.map.addOverlay(this._historyLine);
            this.map.setZoom(this.map.getBoundsZoomLevel(bounds));
            this.map.setCenter(bounds.getCenter());
        }
        else {
        }
    }

    , findLocation: function(lat, lng, latiCap, longiCap) {
        var point = new GLatLng(lat, lng);
        var icon = new GIcon();
        icon.image = "images/red.png";
        icon.iconSize = new GSize(32, 32);
        icon.iconAnchor = new GPoint(6, 20);
        icon.infoWindowAnchor = new GPoint(5, 1);
        if (this._findOutLocationOverlay != null)
            this.map.removeOverlay(this._findOutLocationOverlay);
        this._findOutLocationOverlay = null;
        point = this.realLatLngToMapLatLng(point); //--trans latlng-
        var fmarker = new GMarker(point, icon);
        this._findOutLocationOverlay = fmarker;
        GEvent.addListener(fmarker, "mouseover", function() {
            var WIN_HTML;
            fmarker.openInfoWindowHtml(latiCap + point.lat().toString() + "," + longiCap + point.lng().toString());
        });

        this.map.addOverlay(this._findOutLocationOverlay);
        if (this.meiEarth)
            this.meiEarth.DrawFlagMarker(point, latiCap + point.lat().toString() + "," + longiCap + point.lng().toString());
        this.map.setCenter(point);
    }

    , removeFound: function() {
        if (this._findOutLocationOverlay != null)
            this.map.removeOverlay(this._findOutLocationOverlay);
        this._findOutLocationOverlay = null;
    }

    , findDirection: function(from, to, directionsPanel, language, fnload, fnerror) {
        this.clearDirection();
        this._directions = new GDirections(this.map, directionsPanel);
        GEvent.addListener(this._directions, "load", this.loadDirection);
        var directions = this._directions;
        GEvent.addListener(this._directions, "error", function() {
            if (directions != null) {
                if (directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
                    fnerror(-1);
                else if (directions.getStatus().code == G_GEO_SERVER_ERROR)
                    fnerror(-2);
                else if (directions.getStatus().code == G_GEO_MISSING_QUERY)
                    fnerror(-3);
                else if (directions.getStatus().code == G_GEO_BAD_KEY)
                    fnerror(-4);
                else if (directions.getStatus().code == G_GEO_BAD_REQUEST)
                    fnerror(-5);
                else
                    fnerror(-100);
            }
        });
        var arr = new Array();
        arr.push(from);
        arr.push(to);

        this._directions.loadFromWaypoints(arr, { "locale": language })
        //this._directions.load("from: " + from + " to: " + to, {"locale": language });
    }

    , loadDirection: function(directions) {
        var count = directions.getPolyline().getVertexCount();
        var route = directions.getRoute(0);
        var start = route.getStartGeocode();
        var end = route.getEndGeocode();
        if (imap.map.getCurrentMapType() != G_SATELLITE_3D_MAP)
            return;
        else {
            var startpoint = imap.mapLatLngToRealLatLng(new GLatLng(start.Point.coordinates[1], start.Point.coordinates[0]));
            var endpoint = imap.mapLatLngToRealLatLng(new GLatLng(end.Point.coordinates[1], end.Point.coordinates[0]));
            var earthPolyLineVertex = [];
            earthPolyLineVertex.push(startpoint);
            for (var i = 0; i < count; i++) {
                earthPolyLineVertex.push(imap.mapLatLngToRealLatLng(directions.getPolyline().getVertex(i)));
            }
            earthPolyLineVertex.push(endpoint);
            imap.meiEarth.ShowDirectionInEarth(earthPolyLineVertex, imap.meiEarth);
            var startmarker = imap.meiEarth.CreateEarthMarker(startpoint, "icon_greenA.png", start.address);
            var endmarker = imap.meiEarth.CreateEarthMarker(endpoint, "icon_greenB.png", end.address);
            imap.meiEarth.AddMarker(startmarker);
            imap.meiEarth.AddMarker(endmarker)

        }
    }
    , clearDirection: function() {
        if (this._directions != null) {
            this._directions.clear();
        }
    }

	, drawPOI: function(poiid, name, lat, lng, iconindex, centermap) {
	    var icon = new GIcon();
	    icon.image = "images/poi32.gif";
	    icon.iconSize = new GSize(32, 32);
	    icon.shadowSize = new GSize(22, 20);
	    icon.iconAnchor = new GPoint(6, 20);
	    icon.infoWindowAnchor = new GPoint(5, 1);
	    var pt = this.realLatLngToMapLatLng(new GLatLng(lat, lng));
	    ExMarker.prototype = new GMarker(pt, icon, false);
	    var marker = new ExMarker(pt, icon, false, '<div class="" style="position:absolute;left:30px;style: font-size: 10px;text-align:left;width:200px; height:auto; float:left;"><font style="filter: glow(color=#0000FF,strength=3); height:20px; width:20px;color:red; padding:1px"><span>' + name + '</span></font></div>');
	    this.map.addOverlay(marker);
	    if (this.meiEarth)
	        this.meiEarth.DrawPoi(new GLatLng(lat, lng), name);
	    this._poiOverlayArray.push(marker);
	    if (centermap) {
	        this.map.setCenter(pt);
	    }


	}

	, beginAddPOI: function(submitcap, cancelcap) {
	    this._submitcap = submitcap;
	    this._cancelcap = cancelcap;
	    this.cancelAddEditPOI();
	    this.changeTool(EnumMapToolType.AddPOI);

	}

	, drawAddPOI: function(lat, lng, iconindex, submitcap, cancelcap, fnsubmitname, fncancelname) {
	    if (this._addPOIOverlay != null)
	        this.map.removeOverlay(this._addPOIOverlay);
	    var pt = new GLatLng(lat, lng);
	    var realpt = this.mapLatLngToRealLatLng(pt);
	    var WIN_HTML = '<div style="width: 12em; style: font-size: small"><INPUT id="textpoi" name="textpoi" value=""><INPUT id=butAddPOI type=button value=';
	    WIN_HTML += submitcap + ' name=submit onclick="return submitAddPOI(\'\',' + realpt.lat().toString() + ',' + realpt.lng().toString() + ',' + iconindex + ')">&nbsp;<INPUT id=butCancel type=button value=';
	    WIN_HTML += cancelcap + ' name=cancel onclick="cancelAddEditPOI()"></div>';
	    var icon = new GIcon();
	    icon.image = "images/poi32b.gif";
	    icon.iconSize = new GSize(32, 32);
	    icon.iconAnchor = new GPoint(6, 20);
	    icon.infoWindowAnchor = new GPoint(5, 1);
	    ExMarker.prototype = new GMarker(pt, icon, false);
	    this._addPOIOverlay = new ExMarker(pt, icon, false, '', WIN_HTML);
	    this.map.addOverlay(this._addPOIOverlay);
	    this._addPOIOverlay.openInfoWindowHtml(WIN_HTML);
	}

    , beginEditMovePOI: function(poiid, lat, lng, iconindex, name, submitcap, cancelcap) {
        this._submitcap = submitcap;
        this._cancelcap = cancelcap;
        this._movePOIInfo = new poiInfo(poiid, name, lat, lng, iconindex);
        var container = this;
        this.cancelAddEditPOI();
        this.changeTool(EnumMapToolType.BeginEditMovePOI);

    }

	, drawMovePOI: function(poiid, name, lat, lng, iconindex, submitcap, cancelcap, fnsubmitname, fncancelname) {
	    if (this._movePOIOverlay != null)
	        this.map.removeOverlay(this._movePOIOverlay);
	    var pt = new GLatLng(lat, lng);
	    var realpt = this.mapLatLngToRealLatLng(pt);
	    var WIN_HTML = '<div style="width: 12em; style: font-size: small"><INPUT id="textpoi" name="textpoi" value="' + name + '"><INPUT id=butAddPOI type=button value=';
	    WIN_HTML += submitcap + ' name=submit onclick="return submitEditPOI(' + poiid + ',\'\',' + realpt.lat().toString() + ',' + realpt.lng().toString() + ',' + iconindex + ')">&nbsp;<INPUT id=butCancel type=button value=';
	    WIN_HTML += cancelcap + ' name=cancel onclick="cancelAddEditPOI()"></div>';
	    var icon = new GIcon();
	    icon.image = "images/poi32b.gif";
	    icon.iconSize = new GSize(32, 32);
	    icon.iconAnchor = new GPoint(6, 20);
	    icon.infoWindowAnchor = new GPoint(5, 1);
	    ExMarker.prototype = new GMarker(pt, icon, false);
	    this._movePOIOverlay = new ExMarker(pt, icon, false, '<div class="" style="position:absolute;left:30px;style: font-size: 10px;text-align:left;width:200px; height:auto; float:left;"><font style="filter: glow(color=#0000FF,strength=3); height:20px; width:20px;color:red; padding:1px"><span>' + name + '</span></font></div>');
	    this.map.addOverlay(this._movePOIOverlay);
	    var container = this; ;
	    GEvent.addListener(this._movePOIOverlay, "click", function(latlng) {
	        container.changeTool(EnumMapToolType.Pan);
	        container._movePOIOverlay.openInfoWindowHtml(WIN_HTML);
	    });
	    this._movePOIOverlay.openInfoWindowHtml(WIN_HTML);
	}

    , cancelAddEditPOI: function() {
        if (this._addPOIOverlay != null)
            this.map.removeOverlay(this._addPOIOverlay);
        if (this._movePOIOverlay != null)
            this.map.removeOverlay(this._movePOIOverlay);
        this.changeTool(EnumMapToolType.Pan);
        if (this.meiEarth) {
            this.meiEarth.ClearAllOfEarthMarker();
            this.meiEarth.HideBalloon();
        }
    }

    , drawPOIbyRecords: function(records) {
        this.hidePOI();
        var i = 0;
        if (records.length != undefined)
            for (i = 0; i < records.length; i++) {
            var record = records[i];
            var lat = record.get("latitude");
            var lng = record.get("longitude");
            var name = record.get("poiname");
            var poiid = record.get("poiid");
            var iconindex = record.get("iconindex");
            this.drawPOI(poiid, name, lat, lng, iconindex, false);
        }
        else {
            var record = records;
            var lat = record.get("latitude");
            var lng = record.get("longitude");
            var name = record.get("name");
            var poiid = record.get("poiid");
            var iconindex = record.get("iconindex");
            this.drawPOI(poiid, name, lat, lng, iconindex, false);
        }

        if (this.meiEarth)
            this.meiEarth.ClearAllOfEarthMarker();
    }


    , hidePOI: function() {
        while (this._poiOverlayArray.length > 0) {
            this.map.removeOverlay(this._poiOverlayArray.pop());
        }
        if (this.meiEarth)
            this.meiEarth.HideAllPoi();
    }

    , removeFromMap: function(ids) {
        var index = -1;
        for (i = 0; i < this._trackerinfoLastArray.length; i++) {
            var tmptrackerinfo = this._trackerinfoLastArray[i];
            if (tmptrackerinfo.deviceid == ids) {
                index = i;
                break;
            }
        }
        if (index >= 0)
            this.removeTrackerInfo(this._trackerinfoLastArray[index]);
    }

    // draw a Circle geofence on google map
    , drawCircleGeoFence: function(lat, lng, radius, fcolor, thickness, opacity) {
        var center = new GLatLng(lat, lng);
        if (this._preRadiusGeoFenceOverlay != null)
            this.map.removeOverlay(this._preRadiusGeoFenceOverlay);
        this._preRadiusGeoFenceOverlay = this.drawCircle(center, radius, fcolor, "#f33f00", thickness, opacity);
    }

    , drawAllCircleGeoFence: function(geofenceArray) {
        var i;
        //        if (this._bounds != null)
        //            this._bounds = null;
        //        this._bounds = new GLatLngBounds();
        var pt;
        var maxradius = 0;
        for (i = 0; i < geofenceArray.length; i++) {
            var lat = parseFloat(geofenceArray[i].latitude);
            var lng = parseFloat(geofenceArray[i].longitude);
            var radius = parseInt(geofenceArray[i].radius);
            maxradius = maxradius > radius ? maxradius : radius;
            var inalarm = geofenceArray[i].inalarm == "1" ? true : false;
            var outalarm = geofenceArray[i].outalarm == "1" ? true : false;
            var index = geofenceArray[i].index;
            this.drawExistCircleGeoFence(lat, lng, radius, inalarm, outalarm, index);
            pt = new GLatLng(lat, lng);
        }
        pt = this.realLatLngToMapLatLng(pt);
        //1000m对应放大12级
        var log2n = Math.log(maxradius / 1000) / Math.log(2);
        this.map.setCenter(pt, 12 - Math.floor(log2n));
    }

    , drawExistCircleGeoFence: function(lat, lng, radius, inalarm, outalarm, index) {
        /***********************
        *用于显示存在的GeoFence
        **************************/

        var center = new GLatLng(lat, lng);
        var ss = (radius / (Math.cos(lat / 90) * 6378137) * 180) / Math.PI;
        var html = _TrackerMain_Index + ":" + index;
        html += "<br>" + _TrackerMain_Radius + ":" + radius + "m";
        html += "<br>" + _TrackerMain_Latitude + ":" + lat + "," + _TrackerMain_Longitude + ":" + lng;
        html += "<br>" + _TrackerMain_InAlarm + ":" + getBooleanString(inalarm);
        html += "<br>" + _TrackerMain_OutAlarm + ":" + getBooleanString(outalarm);
        if (inalarm && outalarm) {
            this.drawCircle(center, ss, "#f33f00", "green", 1, 0.5, html);
        }
        else if (inalarm) {
            this.drawCircle(center, ss, "#f33f00", "red", 1, 0.5, html);
        }
        else if (outalarm) {
            this.drawCircle(center, ss, "#f33f00", "blue", 1, 0.5, html);
        }
    }

    //javascript draw circle function
    , drawCircle: function(center, radius, bcolor, fcolor, thickness, opacity, html) {
        var circleQuality = 1;
        var M = Math.PI / 180;
        var L = this.map.getBounds();
        var sw = L.getSouthWest();
        var ne = L.getNorthEast();
        var circleSquish = 1.4;

        var points = [];
        for (var i = 0; i < 360; i += circleQuality) {
            if (i % 16 == 0) {
                var P = new GLatLng(center.lat() + (radius * Math.sin(i * M)), center.lng() + (radius * Math.cos(i * M)) * circleSquish);
                points.push(P);
            }
        }
        points.push(points[0]);
        //var p = new GPolyline(points, color, thickness, opacity);
        var p = new GPolygon(points, bcolor, thickness, 1, fcolor, opacity);
        var me = this;
        if (html) {
            GEvent.addListener(p, "mouseover", function() {
                me.map.openInfoWindowHtml(center, html);
            });
        }
        this.map.addOverlay(p);
        return p;
    }

    //find locations
    , findLocations: function(addressName, fncallback) {
        this._geocoder.reset();
        this._geocoder.getLocations(addressName, function(response) {
            if (response.Status.code == 200) {
                var place = response.Placemark[0];
                var coordinates = place.Point.coordinates;
                if (fncallback != null)
                    fncallback(coordinates[1], coordinates[0]);
            }
            else {
                fncallback("");
            }
        });
    },
    //解决从谷歌地球切换到谷歌地图位移
    solveExcursionFromEarth: function() {
        this.map.setCenter(this.realLatLngToMapLatLng(this.map.getCenter()));
    },

    resetStartBtn: function(startbtn, stop, cont) {
        if (startbtn) {
            if (startbtn.tooltip.text == stop) {
                this.stopAnimate();
                startbtn.setTooltip({ text: cont, autoHide: true });
                startbtn.setIcon('images/player_play.png');
            }
        }
    },

    clearRoute: function() {
        this._finishDrawRoute = false;
        for (var i = 0; i < this._routePolys.length; i++) {
            this.map.removeOverlay(this._routePolys[i]);
        }
        this._routePolys = [];
        for (var j = 0; j < this._waypoints.length; j++) {
            this.map.removeOverlay(this._waypoints[j]);
        }
        this._waypoints = [];
        this._routeNodes = [];
        this.map.closeInfoWindow();
        this._myNode.hide();
        this._isEditMode = false;
        this._tempRoutes = [];
        this._modifyRouteIndex = 0;
    },

    getMyDragNodeMarker: function(my) {
        var iconNode = new GIcon(); iconNode.image = 'images/node.gif';
        iconNode.shadow = ''; iconNode.iconSize = new GSize(10, 10); iconNode.shadowSize = new GSize(0, 0);
        iconNode.iconAnchor = new GPoint(5, 5); iconNode.infoWindowAnchor = new GPoint(5, 5);
        iconNode.dragCrossImage = 'images/empty.gif'; // undocumented String: indicates an image to be used as the drag cross. If you set it to the null string, you get the default drag_cross_67_16.png image.
        iconNode.dragCrossSize = GSize(1, 1); //undocumented GSize(): indicates the size of the drag cross.
        iconNode.maxHeight = 1; //undocumented integer: The maximum difference in height between the marker anchor and the drag cross anchor during dragging. Setting the maxHeight to zero causes it to use the default 13.
        // create marker for displaying and dragging when mouse is over displayed route
        var myNode = new GMarker(new GLatLng(1, 1), { icon: iconNode, draggable: true, bouncy: false });
        GEvent.addListener(myNode, "dragend", function() { // when user finished dragging the line, create new waypoint with permanent marker at the location
            my._isMyDragging = false;
            my._isFirstDragMyNode = true;
        });
        return myNode;
    },

    getStartAndEndMarker: function(point, my, isEdit, name, distance) {
        var icon = new GIcon();
        icon.image = "images/mm_20_white.png";
        icon.shadow = "images/mm_20_shadow.png";
        icon.iconSize = new GSize(12, 20);
        icon.shadowSize = new GSize(22, 20);
        icon.iconAnchor = new GPoint(6, 20);
        icon.infoWindowAnchor = new GPoint(5, 1);
        var marker = new GMarker(point, { icon: icon, draggable: true, dragCrossMove: false, bouncy: false });
        GEvent.addListener(marker, "dragstart", function() { my._isDragged = 1; my._myNode.hide(); });
        GEvent.addListener(marker, "drag", function() { var dMarker = this; my.dragMarker(dMarker); });
        GEvent.addListener(marker, "dragend", function() { my._isDragged = 0; my._tempRoutes.clear(); });
        GEvent.addListener(marker, "click", function() {
            var pointsString = "";
            var poly = my._routePolys[marker.MyIndex - 1];
            for (var i = 0; i <= poly.getVertexCount() - 1; i++) {
                var p = poly.getVertex(i);
                p = my.mapLatLngToRealLatLng(p);
                if (i == 0) {
                    pointsString = p.x + "," + p.y;
                }
                else {
                    pointsString += "|" + p.x + "," + p.y;
                }
            }
            var WIN_HTML = "";
            if (isEdit)
                var WIN_HTML = '<div style="width: 12em; style: font-size: small">' + _TAInfoResource_Name + ':<INPUT id="my_route_line" style="width:100px" value="' + name + '"/><br/>' + _TrackerMain_Distance + ':<INPUT id="my_route_line_distance" style="width:100px" value="' + distance + '"/><br/><INPUT  type="button" value="';
            else
                var WIN_HTML = '<div style="width: 12em; style: font-size: small">' + _TAInfoResource_Name + ':<INPUT id="my_route_line" style="width:100px" value=""/><br/>' + _TrackerMain_Distance + ':<INPUT id="my_route_line_distance" style="width:100px" value="1000"/><br/><INPUT  type="button" value="';
            // '<input name="far_or_close_route" checked=true type="radio" value="0">' + my._farCap + '</input>&nbsp;<input name="far_or_close_route" type="radio" value="1">' + my._closeCap + '</input>&nbsp;
            if (isEdit == true) {
                WIN_HTML += my._submitAddRouteCap + '"  onclick="submitAddRouteEvent(\'' + pointsString.toString() + '\',false,\'' + my._editRouteID + '\');"/>&nbsp;<INPUT  type="button" value="';
                WIN_HTML += my._submitAddAllRouteCap + '"  onclick="submitAddRouteEvent(\'' + pointsString.toString() + '\',true);"/>&nbsp;<INPUT  type="button" value="';
            }
            else {
                WIN_HTML += my._submitAddRouteCap + '"  onclick="submitAddRouteEvent(\'' + pointsString.toString() + '\');"/>&nbsp;<INPUT  type="button" value="';
            }
            WIN_HTML += my._cancelAddRouteCap + '"  onclick="cancelAddRouteEvent()"/>&nbsp;</div>';
            this.openInfoWindowHtml(WIN_HTML);
        });
        return marker;
    },

    setRouteCap: function(okCap, cancelCap, farCap, closeCap, allOkCap) {
        this._submitAddRouteCap = okCap;
        this._submitAddAllRouteCap = allOkCap;
        this._cancelAddRouteCap = cancelCap;
        this._farCap = farCap;
        this._closeCap = closeCap;
    },

    getProximity: function(mouseLatLng) {
        if (this._finishDrawRoute == false)
            return;

        var zoom, point;
        var dist = 0;
        zoom = this.map.getZoom();
        if (this._routeNodes.length == 0) {
            for (var i = 0; i < this._routePolys.length; i++) {
                dist += this._routePolys[i].getLength();
                var last_point;
                for (var j = ((i == 0) ? 0 : 1); j < this._routePolys[i].getVertexCount(); j++) {
                    var point = this._normalProj.fromLatLngToPixel(this._routePolys[i].getVertex(j), zoom);
                    this._routeNodes.push({ point: point, lineindex: i });
                    last_point = point;
                }
            }
        }
        var panel;
        var l = this._routeNodes.length;

        if (!mouseLatLng || l <= 1 || this._isDragged > 0) // no route is displayed or route is already being dragged
            return;

        zoom = this.map.getZoom();
        var mousePx = this._normalProj.fromLatLngToPixel(mouseLatLng, zoom);
        var mouseX = mousePx.x;
        var mouseY = mousePx.y;
        var x = this._routeNodes[0].point.x;
        var y = this._routeNodes[0].point.y;
        var minX = x; // we will search closest point on the line to mouse position for displaying marker there available for dragging
        var minY = y;
        var minDist = 99999;
        for (var n = 0; n < l; n++) {
            var x0 = x;
            var y0 = y;
            x = this._routeNodes[n].point.x;
            y = this._routeNodes[n].point.y;

            if ((x < mouseX - 50 && x0 < mouseX - 50) || (x > mouseX + 50 && x0 > mouseX + 50)) {
                continue;
            }

            if ((y < mouseY - 50 && y0 < mouseY - 50) || (y > mouseY + 50 && y0 > mouseY + 50)) {
                continue;
            }

            var dx = x - x0;
            var dy = y - y0;
            var d = dx * dx + dy * dy; // lenght^2 of segment n

            var u = ((mouseX - x) * dx + (mouseY - y) * dy) / d; // a bit of vector algebra :)
            var x2 = x + (u * dx); // x,y coordinates in pixels of closest point to mouse in segment n
            var y2 = y + (u * dy);

            var dist = (mouseX - x2) * (mouseX - x2) + (mouseY - y2) * (mouseY - y2); // distance^2 from mouse to closest point in segment n

            if (minDist > dist) { // closest point in segment n is closest point overall so far
                var d1 = (mouseX - x0) * (mouseX - x0) + (mouseY - y0) * (mouseY - y0); // distance^2 from mouse to end of segment n in pixels
                var d2 = (mouseX - x) * (mouseX - x) + (mouseY - y) * (mouseY - y)
                if ((d1 - dist) + (d2 - dist) > d) { // closest point is outside the segment, so the real closest point is either start or end of segment
                    if (d1 < d2) {
                        dist = d1;
                        x2 = x0;
                        y2 = y0;
                    }
                    else {
                        dist = d2;
                        x2 = x;
                        y2 = y;
                    }
                }
            }

            if (minDist > dist) { // closest point in segment n is closest point overall so far
                minDist = dist;
                minX = x2;
                minY = y2;
                this._myNode.MyIndex = this._routeNodes[n].lineindex; // remember index of segment closest to mouse
                this._myNode.NodeIndex = n;
            }
        }

        if (minDist > 2500) { // mouse is not close enough to the displayed line
            if (this._isMyNodeStartDrag == false)
                this._myNode.hide(); // do not display marker for dragging the polyline
        }
        else {
            for (n = this._waypoints.length; --n >= 0; ) { // check if mouse is not too close to existing waypoints markers
                var markerPx = this._normalProj.fromLatLngToPixel(this._waypoints[n].getPoint(), zoom);

                dx = markerPx.x - minX;
                dy = markerPx.y - minY;

                if (dx * dx + dy * dy < 25) { // mouse is too close to existing marker
                    this._myNode.hide(); // do not show additional marker for dragging the line - the user is about to drag existing waypoint
                    return;
                }
            }
            if (this._isMyNodeStartDrag == false) {
                this._myNode.setPoint(this._normalProj.fromPixelToLatLng(new GPoint(minX, minY), zoom));
                this._myNode.show(); // display marker for dragging the polyline
            }
        }
    },
    dragMarker: function(dmarker) {
        if (this._isDragged == 2) { // exit if already waiting for GDir2.load to complete
            this._markerDragged = dmarker;
            return;
        }

        if (this._markerDragged) { //determine which marker triggered the recalculation
            marker = this._markerDragged;
            this._markerDragged = false;
        }
        else {
            marker = dmarker;
        }

        this._lastIndex = marker.MyIndex;
        var point = marker.getPoint();
        if (this._lastIndex > 0) {
            if (this._lastIndex < this._waypoints.length - 1) {
                this._prevIndex = this._lastIndex - 1;
                this.GDir2.loadFromWaypoints([this._waypoints[lastIndex - 1].getPoint(), point.toUrlValue(6), this._waypoints[lastIndex + 1].getPoint()], { getPolyline: true });
                this._isDragged = 2; // tag that calculation of new route is started
            }
            else {
                this._prevIndex = -1; this._lastIndex = this._lastIndex - 1; // recalculate path to this point
                this.GDir2.loadFromWaypoints([this._waypoints[this._lastIndex].getPoint(), point.toUrlValue(6)], { getPolyline: true });
                this._isDragged = 2; // tag that calculation of new route is started
            }
        }
        else if (this._waypoints.length > 1) {
            this._prevIndex = -1;
            this.GDir2.loadFromWaypoints([point.toUrlValue(6), this._waypoints[1].getPoint()], { getPolyline: true });
            this._isDragged = 2; // tag that calculation of new route is started
        }

    },
    //显示路线
    showCommonRoute: function(points) {
        var pArray = points.split(',');
        var gPoints = new Array();
        for (var i = 0; i < pArray.length; i += 2) {
            gPoints.push(new GLatLng(pArray[i + 1], pArray[i]));
        }
        if (gPoints.length > 1) {
            var poly = new GPolyline(gPoints, "blue", 10, 0.5);
            this.map.addOverlay(poly);
            this.map.setZoom(this.map.getBoundsZoomLevel(poly.getBounds()));
            this.map.setCenter(poly.getBounds().getCenter());
        }
    },
    //编辑时显示路线在地图
    showOneEditRoute: function(sssid, points, name, distance) {
        this._isEditMode = true;
        var my = this;
        this._editRouteID = sssid;
        var pArray = points.split(',');
        var gPoints = [];
        var bound = new GLatLngBounds();
        var sMarker, eMarker;
        for (var i = 0; i < pArray.length; i += 2) {
            var point = this.realLatLngToMapLatLng(new GLatLng(pArray[i + 1], pArray[i]));
            gPoints.push(point);
            bound.extend(point);
            if (i == 0)
                sMarker = this.getStartAndEndMarker(point, my, true, name, distance);
            else if (i == pArray.length - 2)
                eMarker = this.getStartAndEndMarker(point, my, true, name, distance);
        }

        var poly = new GPolyline(gPoints, "blue", 5, 0.5);
        this._waypoints = [];

        this._finishDrawRoute = true;


        this._waypoints.push(sMarker);
        this.map.addOverlay(sMarker);
        sMarker.MyIndex = 0;
        this._waypoints.push(eMarker);
        this.map.addOverlay(eMarker);
        eMarker.MyIndex = 1;

        if (this._waypoints.length > 1) { // if this was not the first waypoint - display the route to this waypoint
            this.map.addOverlay(poly);
            this._routeNodes = []; this._routePolys = [poly];
            this.getProximity();
        }

        this.map.setZoom(this.map.getBoundsZoomLevel(bound));
        this.map.setCenter(bound.getCenter());

    },
    redrawDefinedRouteToEarth: function() {
        var points = [];
        if (this._routePolys.length > 0) {
            var poly = this._routePolys[this._routePolys.length - 1];
            for (var i = 0; i <= poly.getVertexCount() - 1; i++) {
                var p = poly.getVertex(i);
                p = this.realLatLngToMapLatLng(p);
                points.push(p);
            }
            var newpoly = new GPolyline(points, "blue", 5, 0.5);
            this.map.removeOverlay(poly);
            this.map.addOverlay(newpoly);
            this._routePolys[this._routePolys.length - 1] = newpoly;
        }
    },
    redrawDefinedRouteToMap: function() {
        var points = [];
        if (this._routePolys.length > 0) {
            var poly = this._routePolys[this._routePolys.length - 1];
            for (var i = 0; i <= poly.getVertexCount() - 1; i++) {
                var p = poly.getVertex(i);
                p = this.mapLatLngToRealLatLng(p);
                points.push(p);
            }
            var newpoly = new GPolyline(points, "blue", 5, 0.5);
            this.map.removeOverlay(poly);
            this.map.addOverlay(newpoly);
            this._routePolys[this._routePolys.length - 1] = newpoly;
        }
    },
    iniRouteStep: function() {
        this.map.removeOverlay(this._routePolys[this._routePolys.length - 1]);
        var points = [];
        for (var i = 0; i < this._tempRoutes[this._modifyRouteIndex].getVertexCount() - 1; i++) {
            points.push(this._tempRoutes[this._modifyRouteIndex].getVertex(i));
        }
        var currentRoute = new GPolyline(points, "blue", 5, 0.5);
        this.map.addOverlay(currentRoute);
        this._routePolys.clear();
        this._routePolys.push(currentRoute);
        this._routeNodes = [];
        this.getProximity();
    },

    goPrevDefinedRouteStep: function(button) {
        this._modifyRouteIndex--;
        if (this._modifyRouteIndex <= 0) {
            this._modifyRouteIndex = 0;
            button.setDisabled(true);
        }
        this._routeNextButton.setDisabled(false);
        this.iniRouteStep();
    },
    goNextDefinedRouteStep: function(button) {
        this._modifyRouteIndex++;
        if (this._modifyRouteIndex >= this._tempRoutes.length - 1) {
            this._modifyRouteIndex = this._tempRoutes.length - 1;
            button.setDisabled(true);
        }
        this._routePrevButton.setDisabled(false);
        this.iniRouteStep();
    },
    drawRouteLine: function(fn) {
        this.changeTool(EnumMapToolType.DrawDefinedRoute);
        if (fn) this._callbackDrawPolyline = fn;
    },

    openStreetViewMode: function() {
        this.changeTool(EnumMapToolType.StreetMode);
        this.map.addOverlay(this._svOverlay);
    },

    openMapMode: function() {
        this.changeTool(EnumMapToolType.Pan);
        this.map.removeOverlay(this._svOverlay);
    },

    startDrawPolygonGeofence: function(type, fnAddPg, callbackFn) {
        if (type == 0) {
            this.changeTool(EnumMapToolType.DrawPolygonGeoFenceInAlarm);
        }
        else if (type == 1) {
            this.changeTool(EnumMapToolType.DrawPolygonGeoFenceOutAlarm);
        }
        else if (type == 2) {
            this.changeTool(EnumMapToolType.DrawPolygonGeoFenceInOutAlarm);
        }
        if (fnAddPg)
            this._fnAddPolygonFence = fnAddPg;
        if (callbackFn)
            this._callbackDrawPolygon = callbackFn;
    },

    createPolygon: function(isEdit, pointArray, showInfo) {
        var closeFnName = "imap.closePolygonAndInfoWindow()";
        var submitFnName = "imap._fnAddPolygonFence";
        var polygon = new GPolygon(pointArray, 'blue', 1, 1, 'blue', 0.1);
        if (isEdit) {
            closeFnName = "imap.hideCanEditPolygonFence()";
            submitFnName = "imap._fnEditPolygonFence";
        }
        var my = this;
        GEvent.addListener(polygon, "endline", function() {
            var count = this.getVertexCount();
            var allPointsString = "";
            for (var i = 0; i < count; i++) {
                var point = this.getVertex(i);
                if (i == 0) {
                    allPointsString = point.lat() + "," + point.lng();
                }
                else {
                    allPointsString += "|" + point.lat() + "," + point.lng();
                }
            }
            if (my._callbackDrawPolygon)
                my._callbackDrawPolygon(allPointsString, count);
        });
        if (showInfo) {//这个是pcstrack定制的
            GEvent.addListener(polygon, "click", function(latlng) {
                var pointsString = "";
                for (var i = 0; i <= this.getVertexCount() - 1; i++) {
                    var p = this.getVertex(i);
                    p = my.mapLatLngToRealLatLng(p);
                    if (i == 0)
                        pointsString = p.x + "," + p.y;
                    else
                        pointsString += "|" + p.x + "," + p.y;
                }
                var WIN_HTML = '<div style="width: 12em; style: font-size: small">' +
                                        _TxtName + '<INPUT id="txt_polygon_fence_name" style="width:120px" />' +
                                        '<br/><INPUT id="btn_add_pg_geofence" type="button" value="';
                WIN_HTML += _TxtSave + '"onclick="' + submitFnName + '(\'' +
                        pointsString.toString() + '\');">&nbsp;' +
                        '<INPUT id="btn_cancel_pg_geofence" type="button" value="';
                WIN_HTML += _TxtCancel + '"onclick="' + closeFnName + '"></div>';
                my.map.openInfoWindowHtml(latlng, WIN_HTML);
            });
        }
        return polygon;
    },

    closePolygonAndInfoWindow: function() {
        //完成添加多边形报警后执行的
        this.map.closeInfoWindow();
        if (this._polygonGeofence != null) {
            this._polygonGeofence.hide();
            this._polygonGeofence.disableEditing();
            var count = this._polygonGeofence.getVertexCount();
            while (count > 0) {
                count--;
                this._polygonGeofence.deleteVertex(count);
            }
            this._polygonGeofencePoints.clear();
            this.changeTool(EnumMapToolType.Pan);
        }
    },

    getEditPolygonFenceStatus: function() {
        return this._editPolygonFenceStatus;
    },

    showCanEditPolygonFence: function(pointsString, fnEdit) {
        var my = this;
        this._fnEditPolygonFence = fnEdit;
        var pointStringArray = String(pointsString).split(',');
        var pointArray = new Array();
        var i = 0;
        for (; i < pointStringArray.length; i += 2) {
            var point = new GLatLng(parseFloat(pointStringArray[i + 1]), parseFloat(pointStringArray[i]));
            pointArray.push(point);
        }
        this.hideCanEditPolygonFence();
        if (this._editPolygonFence != null) {
            for (i = 0; i < pointArray.length - 1; i++)
                this._editPolygonFence.insertVertex(i, pointArray[i]);
            this._editPolygonFence.enableEditing();
            this._editPolygonFence.enableDrawing();
            this._editPolygonFence.show();
        }
        this._editPolygonFenceStatus = true;
    },



    hideCanEditPolygonFence: function() {
        if (this._editPolygonFence != null) {
            this._editPolygonFence.disableEditing();
            this._editPolygonFence.hide();
            var count = this._editPolygonFence.getVertexCount();
            while (count > 0) {
                count--;
                this._editPolygonFence.deleteVertex(count);
            }
        }
        this.closePolygonAndInfoWindow();
        this._editPolygonFenceStatus = false;
    },

    getAndSetViewPolygonModel: function() {
        var orginViewModel = this._polygonViewModel;
        this._polygonViewModel = !this._polygonViewModel;
        return orginViewModel;
    },

    hideAllCannotEditPolygonFence: function() {
        while (this._polygonFenceShowArray.length > 0) {
            var i = this._polygonFenceShowArray.length - 1;
            this.map.removeOverlay(this._polygonFenceShowArray[i]);
            if (this._polygonFenceShowArray[i].label)
                this.map.removeOverlay(this._polygonFenceShowArray[i].label);
            this._polygonFenceShowArray.remove(this._polygonFenceShowArray[i]);
        }
    },

    showCannotEditPolygonFence: function(pointsString, token, focusToCenter, name) {
        var pointStringArray = String(pointsString).split(',');
        var pointArray = new Array();
        var i = 0;
        var isExist = false;
        var me = this;
        for (; i < pointStringArray.length; i += 2) {
            var point = new GLatLng(parseFloat(pointStringArray[i + 1]), parseFloat(pointStringArray[i]));
            pointArray.push(point);
        }
        for (i = 0; i < this._polygonFenceShowArray.length; i++) {
            if (this._polygonFenceShowArray[i].token == token) {
                this.setCenter(this._polygonFenceShowArray[i].getBounds().getCenter(), 12);
                isExist = true;
                return;
            }
        }
        if (!isExist) {
            var polygon = this.createPolygon(false, pointArray, false);
            polygon.token = token;
            GEvent.addListener(polygon, "click", function(latlng) {
                me.map.removeOverlay(this);
                if (this.label)
                    me.map.removeOverlay(this.label);
                me._polygonFenceShowArray.remove(this);
            });
            this._polygonFenceShowArray.push(polygon);
            this.map.addOverlay(polygon);

            if (name) {
                var label = new TLabel(polygon.getBounds().getCenter());
                label.setContent("<div class='polygon-geofence-label'>" + name + "</div>");
                polygon.label = label;
                this.map.addOverlay(polygon.label);
            }
            if (focusToCenter)
                this.setCenter(polygon.getBounds().getCenter(), 12);
        }
    },

    hideCannotEditPolygonFence: function(token) {
        for (var i = 0; i < this._polygonFenceShowArray.length; i++) {
            if (this._polygonFenceShowArray[i].token == token) {
                this.map.removeOverlay(this._polygonFenceShowArray[i]);
                if (this._polygonFenceShowArray[i].label)
                    this.map.removeOverlay(this._polygonFenceShowArray[i].label);
                this._polygonFenceShowArray.removeAt(i);
                break;
            }
        }
    },

    drawNewPolygonFence: function(pt) {
        this._polygonGeofencePoints.push(pt);
        var vertex = this.createPointMarker(pt);
        this.map.addOverlay(vertex);
        this._polygonGeofenceVertexs.push(vertex);
        //绘制线段
        if (this._polygonGeofencePoints.length > 1) {
            var lastIndex = this._polygonGeofencePoints.length - 1;
            var path = new GPolyline([this._polygonGeofencePoints[lastIndex - 1],
            this._polygonGeofencePoints[lastIndex]], 'blue', 1, 0.8);

            if (this._polygonGeofencePaths.length >= 3) {
                this.map.removeOverlay(this._polygonGeofencePaths[this._polygonGeofencePaths.length - 1]);
                this._polygonGeofencePaths.removeAt(this._polygonGeofencePaths.length - 1);
            }
            this._polygonGeofencePaths.push(path);
            this.map.addOverlay(path);
            if (this._polygonGeofencePaths.length >= 2) {
                var lastPath = new GPolyline([this._polygonGeofencePoints[lastIndex], this._polygonGeofencePoints[0]],
                                              'blue', 1, 0.8);
                this._polygonGeofencePaths.push(lastPath);
                this.map.addOverlay(lastPath);
            }
        }

        //绘制多边形
        if (this._polygonGeofencePoints.length > 2) {
            var i = 0;
            //删除所有点
            for (; i < this._polygonGeofenceVertexs.length; ) {
                this.map.removeOverlay(this._polygonGeofenceVertexs[i]);
                this._polygonGeofenceVertexs.removeAt(i);
            }
            //删除所有线段
            for (i = 0; i < this._polygonGeofencePaths.length; ) {
                this.map.removeOverlay(this._polygonGeofencePaths[i]);
                this._polygonGeofencePaths.removeAt(i);
            }
            if (this._polygonGeofence != null) {
                this._polygonGeofence.enableEditing();
                this._polygonGeofence.enableDrawing();
                this._polygonGeofence.show();
                if (this._polygonGeofence.getVertexCount() >= 3)
                    return;
                else {
                    for (i = 0; i < this._polygonGeofencePoints.length; i++)
                        this._polygonGeofence.insertVertex(i, this._polygonGeofencePoints[i]);
                }

            }
        }
    },
    showDeviateRouteAndParking: function(points, fncallback) {
        var polyLineArray = new Array();
        var gPointArray = new Array();
        var bound = new GLatLngBounds();
        var i = 0;
        for (; i < points.length; i++) {
            var myPoint = new GLatLng(points[i].latitude, points[i].longitude);
            bound.extend(myPoint);
            if (points[i].is_stop_point && points[i].is_deviate_point) {
                var stopMarker = this.createStoppedMarker(myPoint, _Alarm_ParkingTime + ":" + points[i].stop_time + "(" + _InputReportResource_Minutes + ")");
                this.map.addOverlay(stopMarker);
            }
            if (i == 0) {
                gPointArray.push({ point: myPoint, deviate: points[i].is_deviate_point, journey: points[i].Journey });
            }
            else {
                var d1 = gPointArray[gPointArray.length - 1].deviate;
                var d2 = points[i].is_deviate_point;
                if (gPointArray[gPointArray.length - 1].deviate == points[i].is_deviate_point) {


                    gPointArray.push({ point: myPoint, deviate: points[i].is_deviate_point, journey: points[i].Journey });
                    if (i == points.length - 1) {
                        var tempArray = new Array();
                        for (var index = 0; index < gPointArray.length; index++) {
                            tempArray.push(gPointArray[index]);
                        }
                        polyLineArray.push({ points: tempArray, isDeviate: points[i].is_deviate_point });
                    }
                }
                else {
                    gPointArray.push({ point: myPoint, deviate: points[i].is_deviate_point, journey: points[i].Journey });
                    var tempArray = new Array();
                    for (var index = 0; index < gPointArray.length; index++) {
                        tempArray.push(gPointArray[index]);
                    }
                    polyLineArray.push({ points: tempArray, isDeviate: !points[i].is_deviate_point });
                    gPointArray.clear();
                    gPointArray.push({ point: myPoint, deviate: points[i].is_deviate_point, journey: points[i].Journey });
                }
            }
        }

        var totalJourney = 0;
        for (i = 0; i < polyLineArray.length; i++) {
            var color = "blue";
            var journey = 0;
            var isDeviate = polyLineArray[i].isDeviate;
            if (isDeviate) {
                journey = polyLineArray[i].points[polyLineArray[i].points.length - 1].journey - polyLineArray[i].points[0].journey;
                totalJourney += journey;
                color = "red";
            }
            var myLinePointArray = new Array();
            for (var j = 0; j < polyLineArray[i].points.length; j++) {
                myLinePointArray.push(polyLineArray[i].points[j].point);
            }
            if (myLinePointArray.length > 1) {
                var poly = new GPolyline(myLinePointArray, color, 10, 0.5);
                poly.journey = journey;
                if (isDeviate) {
                    GEvent.addListener(poly, "click", function(latlng) {
                        if (fncallback)
                            fncallback(_TxtTotalDeviate + totalJourney + _TxtOneSectionDeviate + this.journey);
                    });
                }
                this.map.addOverlay(poly);
                this.map.setZoom(this.map.getBoundsZoomLevel(bound));
                this.map.setCenter(bound.getCenter());
            }

        }
        return totalJourney;
    }

    , findAddress: function(keywords, fn) {
        var mapsearch = new GMapExtentSearch(this.map, fn);
        mapsearch.execute(keywords);
    }
};


